---
term: 'Managed Object Storage & Asset Delivery Pipelines'
seoTitle: 'What is Managed Object Storage? Asset Delivery Explained'
headline: 'What is Managed Object Storage & How Do Asset Delivery Pipelines Work?'
slug: managed-object-storage
category: cloud-architecture
shortDefinition: 'Managed object storage is a BaaS service that stores files uploaded through SDKs and serves them via CDN-backed URLs with access control.'
relatedTerms:
  - cdn-content-delivery-network
  - edge-computing-edge-functions
  - baas-vs-custom-backend
  - backend-sdk
contrastsWith:
  - cdn-content-delivery-network
faq:
  - question: 'What is object storage, and how is it different from a file system?'
    answer: '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.'
  - question: 'How do file uploads work in a BaaS?'
    answer: '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.'
  - question: 'What is a storage adapter in Parse Server?'
    answer: '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.'
  - question: 'How does a CDN fit into asset delivery?'
    answer: '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.'
  - question: 'Who can read or write files in a managed object storage setup?'
    answer: '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.'
  - question: 'Should I store files in the database or in object storage?'
    answer: '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.'
  - question: 'What file types and sizes can a BaaS handle?'
    answer: '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.'
  - question: 'How should mobile apps handle large file uploads reliably?'
    answer: '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.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'Object storage (Wikipedia)'
    url: 'https://en.wikipedia.org/wiki/Object_storage'
  - name: 'Content delivery network (Wikipedia)'
    url: 'https://en.wikipedia.org/wiki/Content_delivery_network'
  - name: 'HTTP caching (MDN)'
    url: 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Caching'
  - name: 'Parse Server documentation'
    url: 'https://docs.parseplatform.org/parse-server/guide/'
cta:
  title: 'File storage and delivery, already assembled'
  text: 'Upload a file with one SDK call and get a CDN-backed URL — Back4app runs the storage, the adapter layer, and the delivery pipeline behind it. Attach files to objects, guard them with ACLs, and skip the bucket-and-pipeline assembly project entirely.'
  linkText: 'Start building free'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-08-05'
translationKey: managed-object-storage
---

**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:**

```javascript
// 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
// 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
```

**Swift:**

```swift
// 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
```

**Kotlin:**

```kotlin
// 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:

```mermaid
flowchart LR
  accTitle: Managed object storage upload and delivery pipeline
  accDescr: Uploads flow from the client SDK through the platform API and a storage adapter into object storage, with a reference saved in the database; deliveries flow from the stored file through CDN edge caches to clients requesting the file URL.
  subgraph up["Upload path (writes)"]
    C[Client SDK] -->|"authenticated upload"| A[Platform file API]
    A --> AD["Storage adapter<br/>(GridFS / filesystem / S3-compatible)"]
    AD --> OS[("Object storage")]
    A -->|"file reference"| DB[("Database record<br/>+ ACL")]
  end
  subgraph down["Delivery path (reads)"]
    OS -->|"origin fetch (first request)"| E["CDN edge cache"]
    E -->|"cached response"| U[Users worldwide]
  end
```

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](/glossary/cdn-content-delivery-network/) 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](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Caching) 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](https://docs.parseplatform.org/parse-server/guide/): 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](/glossary/access-control-lists-acl/) — the `Document` in 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](/glossary/backend-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](/glossary/baas-vs-custom-backend/) 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](/glossary/edge-computing-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.
