Managed object storage is a BaaS service that stores files uploaded through SDKs and serves them via CDN-backed URLs with access control. It collapses a pipeline teams otherwise assemble by hand — buckets, upload endpoints, permissions, cache configuration — into two SDK calls: save the file, use the URL. The database holds a reference; the bytes live in storage built for exactly this shape of data.
Key takeaways
| Question | Answer |
|---|---|
| What it is | Platform-run file storage behind the SDK: upload in, URL out |
| The core pattern | Bytes in object storage, references and metadata in the database |
| Delivery path | Storage is the origin; a CDN serves reads from edge caches |
| Security model | Authenticated uploads; reads guarded by ACLs on the referencing object |
| What you skip | Buckets, upload servers, signing logic, cache plumbing |
Upload, attach, protect
The working unit is a file object: the SDK streams the bytes up, the platform returns a stable URL, and you attach the reference to a database record whose ACL controls who finds it:
// JavaScript / Node.js — Back4app JS SDK
// Upload, attach, protect: three steps to a CDN-delivered private file
const file = new Parse.File('report.pdf', fileInput.files[0]);
await file.save(); // streamed to managed object storage
const doc = new Parse.Object('Document');
doc.set('file', file);
doc.set('owner', Parse.User.current());
doc.setACL(new Parse.ACL(Parse.User.current())); // only the owner reads
await doc.save();
console.log(file.url()); // CDN-backed delivery URL — no bucket configured // Flutter / Dart — Back4app Flutter SDK
// Upload, attach, protect: three steps to a CDN-delivered private file
final parseFile = ParseFile(File('report.pdf'));
await parseFile.save(); // streamed to managed object storage
final owner = await ParseUser.currentUser() as ParseUser;
final doc = ParseObject('Document')
..set('file', parseFile)
..set('owner', owner)
..setACL(ParseACL(owner: owner)); // only the owner reads
await doc.save();
print(parseFile.url); // CDN-backed delivery URL — no bucket configured // iOS / Swift — Back4app Swift SDK
// Upload, attach, protect: three steps to a CDN-delivered private file
var file = ParseFile(name: "report.pdf", data: pdfData)
let savedFile = try await file.save() // streamed to managed object storage
var doc = Document()
doc.file = savedFile
doc.owner = try await User.current()
var acl = ParseACL()
acl.setReadAccess(user: doc.owner!, value: true)
acl.setWriteAccess(user: doc.owner!, value: true) // only the owner reads
doc.ACL = acl
_ = try await doc.save()
print(savedFile.url ?? "") // CDN-backed delivery URL — no bucket configured // Android / Kotlin — Back4app Android SDK
// Upload, attach, protect: three steps to a CDN-delivered private file
val file = ParseFile("report.pdf", pdfBytes)
file.save() // streamed to managed object storage
val owner = ParseUser.getCurrentUser()
val doc = ParseObject("Document")
doc.put("file", file)
doc.put("owner", owner)
doc.acl = ParseACL(owner) // only the owner reads
doc.save()
println(file.url) // CDN-backed delivery URL — no bucket configured Nothing in those four tabs mentions a bucket, a region, a signed request, or a cache header — the pipeline behind the call owns all of it.
The pipeline behind the call
Two flows share the infrastructure, with opposite performance profiles. Uploads are rare and consistency-critical; reads are massive and latency-critical. The pipeline splits them accordingly:
The right half is where the economics live. Assets are written once and read thousands to millions of times, so serving reads from edge caches rather than the origin decides both latency and cost. Aggressive caching is safe because stored files are immutable-by-convention — replacing an avatar uploads a new file with a new URL rather than mutating the old one, which sidesteps the cache-invalidation problem entirely.
Managed object storage vs. a plain CDN
The two are routinely conflated because both end in “fast file URLs” — but they solve different halves of the problem:
| Dimension | Managed object storage | Plain CDN |
|---|---|---|
| What it is | The system of record for your files | An acceleration layer for files hosted elsewhere |
| Origin | Included — storage is the origin | You must supply and run one |
| Uploads | First-class SDK operation | Out of scope — write to the origin yourself |
| Access control | ACLs via the referencing database object | Cache rules and signed URLs you configure |
| Database integration | File references attach to app records natively | None — you build the bookkeeping |
| Best at | Owning the upload-store-protect lifecycle | Squeezing latency out of global delivery |
In a managed pipeline you get both roles pre-wired: storage as the origin, a CDN as its delivery layer, and no seam between them to configure or misconfigure.
Storage adapters: the portability layer
In Parse Server — the open-source engine under Back4app — the file API and physical storage are decoupled by a storage adapter: GridFS keeps files inside MongoDB (the default), a filesystem adapter writes to local disk, and S3-compatible adapters target any conforming object store, hyperscaler or self-hosted. The adapter interface is public, so custom backends are a class away. Clients never notice: save file, get URL is the whole contract, which means storage backends can be swapped — managed to self-hosted, one store to another — without an app release.
Who can read and write files
File security is the least-covered part of most storage tutorials and the first thing an audit asks about. The managed model gives you three layers, with one honest caveat:
- Writes are authenticated. Uploads go through the SDK under a logged-in user (or your server’s credentials) — there is no anonymous public upload endpoint unless you build one. Server-side validation of type and size on upload remains your job.
- Reads are governed by references. The file URL lives on a database object guarded by ACLs — the
Documentin the snippet is readable only by its owner, so only the owner can query their way to the URL. - URLs themselves are bearer tokens. Once a file URL is known, it is typically servable to whoever holds it — CDN-cached content is not re-authorized per request. For genuinely sensitive files, serve downloads through an authenticated function that checks permissions before streaming, and treat plain URL secrecy as what it is: obscurity, useful but not sufficient.
Common use cases
- User-generated media. Avatars, photos, and attachments — upload from the client SDK, store the reference on the user or post, render via the URL.
- Documents with ownership. Invoices, reports, and contracts where the ACL on the referencing record is the permission system.
- App content and game assets. Level packs, media bundles, and remotely updated content served from edge caches instead of shipped in app-store binaries.
- Cross-platform asset sharing. One uploaded file, one URL, rendered identically on iOS, Android, Flutter, and web.
- Pipeline outputs. Generated exports, thumbnails, and processed media written by server-side functions and delivered like any other asset.
Should you use managed storage or build the pipeline? A decision matrix
| Managed object storage when… | Assemble your own pipeline when… |
|---|---|
| Files attach to app data (users, posts, orders) | Assets are a standalone product with their own lifecycle |
| Standard upload/deliver/protect flows cover you | You need transcoding, resumable multi-GB uploads, or DRM |
| Team size argues against owning infrastructure | A dedicated platform team already runs storage |
| Portability matters — adapters keep the exit open | You are optimizing storage cost at petabyte scale |
| Time-to-ship is the constraint | Millisecond-level control of every cache hop is the constraint |
The same build-vs-buy calculus as the broader BaaS decision applies, at file-storage scale: the assembled pipeline is not hard to imitate poorly and quite hard to run well.
Limitations and trade-offs
- URL-based access is coarse. ACLs guard the reference, not each byte-serve of a cached file. Sensitive-document products need authenticated download endpoints on top — plan for the extra hop.
- Size ceilings are real. Platform per-file limits comfortably cover images and documents; long-form video and raw datasets belong in a specialized pipeline with resumable uploads.
- No transformation layer by default. Resizing, transcoding, and watermarking are yours to add — typically as server-side functions or edge functions in front of storage.
- Egress and storage accumulate. Files never garbage-collect themselves; orphaned uploads from abandoned records quietly grow the bill. Schedule cleanup of unreferenced files.
- Cache freshness cuts both ways. Immutable-URL versioning makes updates instant, but if you do overwrite a file in place, edge caches may serve the stale version until TTLs expire — version your URLs and the problem disappears.
Managed object storage on Back4app
Back4app is an open-source Backend-as-a-Service (BaaS) platform that combines a managed database, auto-generated REST and GraphQL APIs, authentication, file storage, and Cloud Code serverless functions. Its file storage is the managed pipeline this article describes: SDK uploads stream through Parse Server’s file API into platform-run object storage, returned URLs are CDN-backed for global delivery, and access control composes with the same ACLs that guard the rest of your data. Because the adapter layer is open-source Parse Server, the files — like the database — remain portable to any deployment you might run yourself.
Frequently asked questions
What is object storage, and how is it different from a file system?
Object storage keeps each file as a self-contained object — data plus metadata under a unique key — in a flat namespace, rather than in a hierarchical file system with directories and file locks. That flatness is what lets it scale to billions of files and expose every object as an HTTP-addressable URL, which is exactly the shape web and mobile asset delivery needs.
How do file uploads work in a BaaS?
The client SDK takes a file, streams it to the platform's file endpoint, and gets back a stable URL. The platform writes the bytes through a storage adapter into object storage and returns a reference you attach to a database object. You never provision buckets, sign upload requests by hand, or run an upload server — the pipeline is the platform's.
What is a storage adapter in Parse Server?
The pluggable layer between the file API and physical storage. Parse Server ships adapters for GridFS (files inside MongoDB, the default), the local filesystem, and S3-compatible object stores, and the interface is open for custom backends. Your client code is adapter-agnostic — save a file, get a URL — so storage backends can change without touching the app.
How does a CDN fit into asset delivery?
Object storage is the origin; the CDN is the delivery layer in front of it. The first request for a file is fetched from storage and cached at an edge server near the user; subsequent requests are served from that cache without touching the origin. Uploads write once to storage, while reads — which outnumber writes enormously for assets — are absorbed at the edge.
Who can read or write files in a managed object storage setup?
Uploads require an authenticated SDK call, so write access follows your app's user model. Read protection comes from the object referencing the file: guard the record with ACLs and only authorized users can retrieve the URL. The honest caveat is that a file URL, once known, is typically servable — so treat URL secrecy as obscurity, and put truly sensitive downloads behind authenticated endpoints.
Should I store files in the database or in object storage?
Metadata in the database, bytes in object storage — the reference pattern. Rows carrying multi-megabyte blobs bloat the database, slow queries and backups, and waste cache memory. A BaaS enforces the healthy split automatically: the file object lives in storage, the database holds a lightweight reference plus queryable metadata like owner, size, and type.
What file types and sizes can a BaaS handle?
Any content type — images, video, audio, PDFs, arbitrary binaries — since object storage is content-agnostic. Size ceilings are set per platform or plan, comfortably covering images and documents; very large media like long-form video usually deserves a dedicated pipeline with resumable uploads and transcoding. Validate type and size server-side on upload regardless.
How should mobile apps handle large file uploads reliably?
Upload in the background off the UI thread, show progress from the SDK's callbacks, and retry on connectivity loss — mobile networks make partial failure the normal case. Compress or resize images client-side before upload when full resolution is not needed; shipping a 12-megapixel photo destined for a 200-pixel avatar wastes battery, bandwidth, and storage.