Skip to main content

Salesforce File Handling: Architecture and Pitfalls

About Us
Published by yuliya.dzemidchuk
26 February 2026

File Handling in Salesforce: Real-World Architecture and Pitfalls

 

The Problem Nobody Talks About

Pick any Salesforce file handling tutorial and you'll find sanitized examples: upload a file, store it in ContentVersion, retrieve it with SOQL. Perfect for demos, useless for production. The moment you need images for a public website, process PDFs with complex layouts, or handle API file size limits, you discover that Salesforce file storage is a minefield of architectural decisions that can make or break your application.

“I've built systems handling everything from CV parsing to auction site galleries. Every approach has brutal trade-offs that documentation conveniently omits. This article covers what actually works, what fails spectacularly, and the architectural decisions you need to make before writing code.”

 

ContentVersion vs Attachment: The Decision That Matters

The Real Differences:

Query Performance: ContentVersion requires three-object joins (ContentVersion → ContentDocument → ContentDocumentLink). Attachment is straightforward parent-child. In loops processing 200 records, ContentVersion hits SOQL limits. Attachment doesn't.

File Sharing: ContentVersion works in Experience Cloud with granular permissions. Attachment access control is primitive - see parent record or nothing.

API Limits: Both support 2GB via UI, but API uploads typically face smaller limits - generally around 38MB for ContentVersion and 25MB for Attachment, though this varies by upload method (REST, SOAP, multipart). Base64 encoding adds 33% overhead, further reducing practical limits.

Version Control: ContentVersion tracks versions natively. Attachment is single-version only.

Use ContentVersion when: file sharing across records, version history, Experience Cloud access. The use of  Attachment is considered a deprecated practice and should be avoided unless there are strict system restrictions.

 

Image Loading: URL vs Base64

Architecture 1: Image URLs
How it works: Store in ContentVersion, generate URLs, browser loads from Salesforce CDN.

✓ Clean separation, browser caching, CDN delivery
✗ Authentication nightmares, URL expiration, CORS issues, no image optimization control, expensive three-object queries

Architecture 2: Base64 Data
How it works: Store binary as a base64 string in the Long Text Area field (max 131,072 characters), render as data:image URLs.

✓ Single object queries, no auth issues, works everywhere, immediate delete, version control
✗ Size limit (~98KB after encoding), SOQL character limits, heap consumption, 33% storage overhead, no CDN, slower browser parsing

Real Implementation:
An auction platform was implemented using both approaches simultaneously, controlled by Custom Metadata (Images_Loading_Type__c). Story thumbnails (<50KB) used Base64 for instant loading. Full-size images (200KB-2MB) used ContentVersion URLs with CDN caching. User profiles used Base64. PDF receipts used ContentVersion for version history.

 

The Heap Limit Nightmare

The 6MB Wall
Apex heap limit: 6MB sync, 12MB async. Base64 encoding adds 33% overhead, and you need memory for BOTH original Blob AND encoded String. Practical limit: ~4MB files before heap explosions.

Real Example:
CV parsing system: retrieve ContentVersion.VersionData, encode base64, send to OpenAI API. Worked perfectly with 500KB test PDFs. Production users uploaded 5MB CVs with embedded images. Heap limit exception. Every. Single. Time.

Solutions:

  • Winter '26 External Services: Use ContentDocument ID pointers instead of loading into the heap. Supports files up to 16MB, depending on the integration pattern and API capabilities.

  • File size validation: Reject >4MB at upload. Simple but user-hostile.

  • External storage: Upload to S3/Google Drive, store reference in Salesforce.

  • Chunking: Split files, process sequentially. Requires API multipart upload support.

     

File Format Hell

Salesforce Has Zero Native Parsing
PDF, DOCX, DOC - Salesforce can't parse any of them. ContentVersion.VersionData gives raw binary. Your options:

  • External API (OpenAI, AWS Textract): Accurate but expensive. Best for complex layouts.

  • Pre-process before upload: Convert to text externally, upload both.

  • Accept plain text only: Simplest but limits user experience.

Real CV Parsing Issues:
PDFs with heavy images return garbage text. Scanned PDFs need OCR (lower accuracy, higher cost). Multi-column layouts confuse extraction order. Solution: Validate format client-side, reject scanned PDFs, provide clear error messages.

 

Security: The Silent Failure Mode

ContentDocument Sharing Complexity:

  • Inferred sharing doesn't work in Communities - requires ContentDistribution

  • Parent record sharing ≠ ContentDocument sharing

  • ContentDocumentLink not included in sharing rules

  • Guest users may need to use ContentDistribution (paid) or Base64 to get access to ContentDocument 

Secure Pattern:
Store sensitive files in ContentVersion with Viewer ShareType. Link only to user-owned records. Use without sharing Apex with custom access logic. For public files, use ContentDistribution with expiration or Base64 in public objects. Log access via Platform Events.

 

Performance Patterns

Loading Strategies:

Lazy Loading: Load on demand. Best for galleries where users view few files. Pros: Fast initial load. Cons: Delay on click.

Eager Loading: Load everything upfront. Best for single-file displays. Pros: Instant display. Cons: Slow if unused.

Hybrid: Load thumbnails eager, full files lazy. Best for most cases. Pros: Fast previews + quality on demand.

Batch Processing Trick:
Don't process files in batch execute() - heap limit applies to entire chunk. Instead, batch creates Queueable jobs for each file. Each Queueable gets its own 12MB heap limit. Failures isolated, better error reporting.

 

Decision Framework

File Size:

Under 50KB → Base64 in custom fields

50KB - 4MB → ContentVersion (careful heap management)

4MB - 16MB → External Services (Winter '26)

Over 16MB → External storage (S3, Drive)

Access Pattern:

Internal users only → ContentVersion + URLs

External/guest users → Base64 or ContentDistribution

Frequent reads → URLs with CDN

Rare reads → Either works

Processing Needs:

Display only → URLs

Text extraction → External API

Image manipulation → Client-side pre-upload

Complex operations → External worker service

 

Top 10 Disasters

  1. Processing in triggers: Always queue async. Triggers have strict limits and shared heap.
  2. Assuming UTF-8: Windows users upload various encodings. Explicitly handle character encoding.
  3. No ContentDocument cleanup: Deleting records doesn't delete files. Storage costs explode.
  4. Loading all files together: Querying VersionData for multiple files blows heap. One at a time.
  5. Trusting file extensions: Extensions lie. Check actual MIME type.
  6. No async error handling: Queueable fails silently. Implement logging and notifications.
  7. Forgetting IsLatest: ContentVersion creates versions on update. Always use IsLatest = true.
  8. Client-side validation only: Users bypass it. Always re-validate in Apex.
  9. Not testing edge cases: Test corrupted, oversized, wrong format, concurrent uploads.
  10. Hardcoding file types: Use Custom Metadata to switch URL/Base64. Build for migration.

 

The Reality Check

There Is No Perfect Solution
Every file handling approach is a compromise. URLs have auth complexity. Base64 has size limits. ContentVersion has query overhead. External storage has integration costs.

What Works:

  • Start with ContentVersion + URLs unless you have specific reasons

  • Move to Base64 for small, frequently-accessed community images

  • Always process files asynchronously

  • Plan for cleanup from day one

  • Test with realistic sizes and formats, not toy examples

  • Use Custom Metadata to switch approaches - you WILL need to refactor

 

Treat File Architecture as a Strategic Decision

In practice, file handling decisions should be driven not only by technical constraints but by business context, expected scale, and long-term maintainability. The "right" approach depends on how often files are accessed, who needs access, how they are processed, and how the system is expected to evolve. A community site serving 10,000 guest users needs different architecture than an internal app for 50 employees. A document management system processing 1,000 PDFs daily needs different infrastructure than a profile picture uploader.

Treat file architecture as a foundational decision — not an implementation detail — because changing it later is expensive. Migrating from Attachment to ContentVersion means rebuilding sharing logic and access patterns. Switching from Base64 to URLs requires data migration and front-end refactoring. Moving from on-platform storage to external services impacts authentication, performance, and compliance.

File handling is where theory meets reality and theory loses. Build for edge cases, test failures, never trust documentation examples. Production files are malformed, oversized, and uploaded by users who don't understand file types. Your architecture needs to handle that, not the happy path. Make architectural decisions early, document the trade-offs, and build flexibility to adapt when requirements inevitably change.


Alexander Zherebilo
Certified Salesforce Developer
image
Expertise
Question to the expert
image

We have available resources to start working on your project within 5 business days

1 UX Designer

image

1 Admin

image

2 QA engineers

image

1 Consultant

image
Related Articles
All articles
image
Is Salesforce Winning the Public Sector Race?
An analysis of Salesforce's rapid expansion into the U.S. public sector, tracing its path from cautious early government licensing deals in the 2010s through the launch of Government Cloud in 2012, its pivotal role in COVID-19 vaccine rollouts, and its 2025–2026 push into military and intelligence work via Agentforce and Missionforce. The piece covers major 2026 contracts — including a $5.6 billion Army deal, a $1.6 billion VA agreement, and Pentagon Impact Level 5 authorization — alongside real-world case studies like California's REAL ID processing and the UK's NHS back-office operations. It also examines the structural obstacles still facing Salesforce and other vendors in government tech: legacy IT systems decades old, outdated federal procurement rules, budget constraints, and organizational caution around AI adoption, plus the competitive pressure from Palantir, Microsoft, and Oracle in the race for public sector AI spending.
28 August 2026
image
Why Your Salesforce Flows Are Agentforce's Biggest Problem
This article argues that the most underestimated risk in Agentforce deployments isn't data quality — it's the automation layer: years of overlapping Flows, Process Builder processes, Apex triggers, and managed package logic that no one has reviewed end-to-end. It explains why AI agents inherit automation complexity without the tribal knowledge human admins carry, why technical debt only becomes visible after an agent hits it in production, and why a clean demo is no indicator of production readiness. The article closes with a concrete, tool-by-tool inventory approach using Flow Trigger Explorer, Salesforce Optimizer, Setup Audit Trail, Apex Debug Logs, Agent Builder, and Health Check — scoped to the specific processes the agent will actually use rather than the whole org.
23 July 2026
image
How to Wire Multiple Salesforce Projects in One Org Without Breaking Everything
This article maps the real integration patterns that emerge when multiple Salesforce projects — both managed packages and unpackaged code — share a single org. It covers four concrete patterns: attaching custom triggers to package-owned objects, calling global members exposed by managed packages, writing directly into another project's objects, and runtime-guarded reads of package data. It then addresses access control for authenticated and guest users, including the Master-Detail wall and the without sharing elevation pattern. The piece closes with eight concrete risks (compile-time dependencies that block uninstall, upgrade coupling, silent cascade failures, access invisible to admins) and six actionable recommendations for keeping cross-project coupling manageable.
08 July 2026