Platforms and integrations

# Choose external storage for a media workflow

Choose an external storage destination for Transloadit workflows by comparing storage models, credentials, access controls, URL behavior, and bulk-import needs.

Published September 2, 2026

## Key takeaways

* Choose the storage model before the vendor: object storage, collaborative file storage, and file-transfer servers solve different operational problems.
* Treat import and export as separate trust boundaries, with least-privilege Template Credentials for only the paths and actions each workflow needs.
* Do not infer public access from a returned URL; bucket policy, sharing settings, signed URLs, and server permissions determine whether a result is retrievable.

Selecting a storage integration is an architecture decision, not a search for a provider name. Object stores, collaborative file services, and file-transfer servers expose different permission models, URL guarantees, listing behavior, and failure modes. This guide groups the supported destinations by those differences so you can choose one workflow deliberately instead of copying nearly identical examples.

## In this guide

1. [Start with the storage model, not the provider logo](#external-storage-media-workflows-section-1)
2. [Match each destination to its Transloadit Robot pair](#external-storage-media-workflows-section-2)
3. [Keep storage credentials scoped and server-controlled](#external-storage-media-workflows-section-3)
4. [Design public, private, signed, and custom-URL delivery deliberately](#external-storage-media-workflows-section-4)
5. [Build one clear export Step before adding provider variations](#external-storage-media-workflows-section-5)
6. [Treat folder imports as resumable inventory work](#external-storage-media-workflows-section-6)
7. [Validate failure recovery and lifecycle ownership](#external-storage-media-workflows-section-7)

## What matters most

* Plan large folder imports around each Robot’s recursion and pagination contract instead of assuming every provider lists trees in the same way.
* Keep stable asset identifiers and Assembly IDs in your application because filenames, folders, links, and provider metadata can change independently.

## Start with the storage model, not the provider logo

Object storage is the natural fit for application-owned media libraries. Amazon S3, Azure Blob Storage, Backblaze B2, Cloudflare R2, DigitalOcean Spaces, Google Cloud Storage, MEGA S4 Object Storage, MinIO, OpenStack Swift, Supabase Storage, Tigris, Wasabi, and Rackspace Cloud Files expose bucket- or container-oriented destinations through their own Transloadit Robots. They still differ in credentials, endpoint or region fields, access controls, and result URLs, so “object storage” describes the architecture rather than a shared configuration format.

Box and Dropbox are account- and folder-oriented cloud file services. Their folders, links, and user-facing permission systems can be valuable when people work with exported files directly. FTP and SFTP instead target file-transfer servers and existing filesystem conventions. Choose those models because a partner or legacy system requires them, not because their path strings happen to resemble object keys.

### Object storage

Prefer this model for application assets addressed by stable keys, lifecycle rules, and provider-controlled bucket or container policy.

### Collaborative storage

Prefer Box or Dropbox when account folders and provider-managed links are part of the required product experience.

### File transfer

Prefer SFTP or FTP when the receiving system is defined by a server account, directory tree, and established transfer contract.

## Match each destination to its Transloadit Robot pair

The destination name maps to an import Robot and a store Robot: `/s3/import` and `/s3/store`, `/azure/import` and `/azure/store`, `/backblaze/import` and `/backblaze/store`, `/box/import` and `/box/store`, `/cloudflare/import` and `/cloudflare/store`, `/digitalocean/import` and `/digitalocean/store`, and `/dropbox/import` and `/dropbox/store`. The same pairing applies to `/ftp`, `/google`, `/mega`, `/minio`, `/sftp`, `/supabase`, `/swift`, `/tigris`, `/wasabi`, and `/cloudfiles`, such as `/sftp/import` with `/sftp/store`.

An import Robot creates files that later Steps can process. A store Robot consumes selected Step results and writes them to the destination. That direction matters when designing permissions and observability: a successful transformation does not prove that export succeeded, and a successful import does not prove that the source will remain available after processing. Record the Assembly’s terminal state and inspect the result for the store Step you actually depend on.

### Explicit inputs

The `use` relationship selects the upstream files; the store Robot does not automatically export every result in the Assembly.

### Explicit destination

A provider-specific Step is the boundary where path, access, metadata, and credential requirements become part of the workflow contract.

### Explicit completion

The application should mark an asset durable only after the required store result has completed and its destination identity is recorded.

## Keep storage credentials scoped and server-controlled

Create provider access in Template Credentials and reference the record by name from a saved Template. The provider still determines what that credential can do. Restrict it to the smallest source and destination paths, operations, buckets, containers, or folders the workflow requires. When a provider supports separate read and write credentials, separation gives you a cleaner revocation boundary and reduces the effect of a mistaken Template.

Do not send raw provider keys in browser-owned Assembly Instructions or use client fields to select an unrestricted destination. Trusted server code should authorize the user, choose a reviewed Template, and supply only bounded business fields such as an asset identifier. If several tenants or destinations share a workflow shape, keep the mapping from tenant to approved Template or credential on that trusted boundary.

### Least privilege

Grant listing and reading only where an import needs them, and writing only where an export is allowed to create objects.

### Separate trust domains

Use different credential records when environments, tenants, source prefixes, or destination permissions should be revoked independently.

### Trusted selection

Keep arbitrary Robot names, endpoint hosts, and credential choices outside requests controlled by an untrusted browser or agent.

## Design public, private, signed, and custom-URL delivery deliberately

Provider integrations do not share one access-control vocabulary. Amazon S3 exposes both `acl` and `sign_urls_for`, while Cloudflare R2 exposes `sign_urls_for` but no `acl` option. Azure uses shared-access signatures. Amazon S3’s Robot default is `public-read`; on a bucket with Block Public Access enabled, that default can fail with a permission error instead of publishing the object. For private S3 delivery, use `private` on buckets that honor object ACLs, or use `bucket-default` when ACLs are disabled or Block Public Access is enabled. The `bucket-default` value defers to the bucket policy and removes the need for `s3:PutObjectAcl`. The Wasabi store Robot instead normalizes an unset `acl` to `private`; set `public-read` explicitly for public Wasabi delivery, or leave it unset or set `private` for private delivery. Wasabi does not support `bucket-default`. Box and Dropbox can create provider sharing links. Other destinations depend primarily on bucket, container, folder, or server configuration outside the Assembly Step.

Keep permission and address generation as separate questions. A URL prefix or URL template can make a result point at a CDN or application hostname, but rewriting an address does not configure the origin, grant read access, or copy the file. Conversely, a private object can have a syntactically valid URL that correctly returns an authorization error. Verify the exact consumer path, expiry behavior, and revocation story for the selected provider.

### Public objects

Use provider policy or an explicit ACL only after deciding whether anonymous retrieval is genuinely part of the product contract.

### Signed access

For controlled access, test signature expiry, clock skew, cached responses, and what happens after an object is replaced or deleted.

### Custom URLs

Treat CDN hostnames and custom URL templates as routing configuration that must agree with the provider’s actual read permissions.

## Build one clear export Step before adding provider variations

A storage workflow should make its data flow obvious. The following Template receives an upload, creates a bounded WebP derivative, and exports only that derivative to Cloudflare R2. The credential name resolves within the Transloadit account, while the path uses Assembly Variables to avoid client-selected provider keys. A production Template should add the validation, naming, metadata, and overwrite policy required by the application.

The same graph shape can inform another destination, but the provider Step is not interchangeable configuration. Replace the store Robot only after reading its schema and deciding how credentials, bucket or folder selection, access, URLs, and collisions should work. Keep separate reviewed Templates when the differences are operationally important, even if their transformation Steps remain identical.

Export one optimized derivative to a scoped Cloudflare R2 destination

```
{
  "steps": {
    ":original": {
      "robot": "/upload/handle"
    },
    "optimized": {
      "use": ":original",
      "robot": "/image/resize",
      "resize_strategy": "fit",
      "width": 1600,
      "height": 1600,
      "format": "webp"
    },
    "exported": {
      "use": "optimized",
      "robot": "/cloudflare/store",
      "credentials": "my-r2-credentials",
      "path": "media/${assembly.id}/${file.id}.${file.ext}"
    }
  }
}
```

## Treat folder imports as resumable inventory work

A single-file import can hide the hard part of a migration. Providers differ in how folders or prefixes are represented, whether traversal is recursive by default or opt-in, how many entries a page returns, and which continuation value requests the next page. Read the selected import Robot’s schema and test a nested fixture that is larger than one page before relying on it for a backfill.

Persist migration intent and progress in your own system. Record the source identity, current page or batch, expected destination identity, Assembly ID, and terminal outcome. Retry idempotently and reconcile counts instead of assuming that re-listing an ever-growing root will identify every missed object cheaply. For ongoing ingestion, prefer durable events or a database-backed manifest over repeated full-bucket scans.

### Representative fixtures

Exercise empty folders, nested names, unusual characters, duplicate basenames, and a listing that crosses at least one page boundary.

### Durable checkpoints

Store progress outside the process so a worker restart does not force a complete relist or silently skip the current page.

### Reconciliation

Compare expected source records with completed destination records and surface missing, duplicated, or superseded objects explicitly.

## Validate failure recovery and lifecycle ownership

Test wrong credentials, a missing source, an unavailable endpoint, a denied destination path, a name collision, an expired signature, and a partial multi-file export. Notifications can be retried, so completion handling must be idempotent. Keep the Assembly ID with the application asset and decide which terminal states may be retried automatically, require operator review, or should leave the source untouched.

Exported storage and Transloadit temporary storage have different owners and lifecycles. A completed Assembly result is not a backup, and deleting an application record does not automatically delete copies in every provider, cache, or temporary processing location. Document retention, replacement, and deletion for the source, derivative, result metadata, and public address, then test those operations as carefully as the initial happy path.

### Duplicate-safe completion

Use an application-level idempotency rule so a repeated callback or retry does not create an unintended second durable asset.

### Step-level observability

Monitor import, transformation, and export separately so a successful upstream Step cannot mask a failed durable handoff.

### Lifecycle contract

Write down which system deletes each source, temporary result, derivative, cached response, and application record, including timing.

## Technical details worth knowing

* Supported destinations use paired import and store Robots, including Amazon S3, Azure Blob Storage, Backblaze B2, Box, Cloudflare R2, DigitalOcean Spaces, Dropbox, FTP, Google Cloud Storage, MEGA S4 Object Storage, MinIO, SFTP, Supabase Storage, OpenStack Swift, Tigris, Wasabi, and Rackspace Cloud Files.
* A store Step exports only results selected by its `use` value, so exporting an original, a derivative, or both is determined by the Assembly graph rather than by the destination provider.
* Template Credentials are account-level records referenced by name, which keeps provider keys out of browser bundles and Assembly Instructions while still requiring the credential itself to be scoped at the provider.
* Access controls are provider-specific: Amazon S3 exposes both `acl` and `sign_urls_for`, Cloudflare R2 exposes `sign_urls_for` but no `acl` option, Azure can produce shared-access signatures, and Box or Dropbox can create sharing links.
* A custom URL prefix or URL template changes the address reported in an Assembly result; it does not by itself grant access, configure a CDN, upload another copy, or prove that the object is publicly readable.
* Import Robots differ in directory traversal, recursive listing, page size, and continuation-token behavior, so a bulk migration must follow the selected Robot schema and persist progress outside a single in-memory loop.
* FTP and SFTP store files on a server filesystem rather than in an object-store namespace; SFTP supports key-based authentication and file-mode configuration, while FTP relies on its own transport and server permission model.
* Temporary Assembly results are not durable application storage, so every result that must survive the temporary retention window should be exported and reconciled with the application’s system of record.

## A practical approach

1. 1\
   Classify the destination by storage model, required region, ownership boundary, and expected retrieval path.
2. 2\
   Create least-privilege Template Credentials and test import and store permissions independently.
3. 3\
   Verify private, public, signed, expired, replaced, and deleted-object behavior with representative files.
4. 4\
   Test pagination, recursive imports, retries, duplicate exports, and partial failures before migrating production traffic.

A four-stage media workflow

## When Transloadit is useful

Use a native Transloadit import or store Robot when a workflow should move files between processing and a supported storage service without your application proxying the bytes. Choose the destination from operational requirements first, then configure its credentials and access behavior explicitly.

## Architecture boundary

Transloadit imports files, processes them, and exports selected results through the configured Robot. The destination remains responsible for durable storage, bucket or folder policy, object lifecycle, replication, and delivery. Your application remains responsible for user authorization, asset records, publication decisions, and deletion across every copy.

## Frequently asked questions

### Does a result URL mean the exported file is public?

No. The address in an Assembly result describes where a provider or configured URL mapping says the object lives. Whether a caller can retrieve it still depends on bucket policy, an object ACL, a provider sharing link, a valid signature, or filesystem and web-server permissions. Test access from an unauthenticated client instead of treating the presence of `url` or `ssl_url` as a permission check.

### Should imports and exports share one credential?

Usually not. Give an import credential only read and list access to the necessary source prefix, and give an export credential only write access to its destination prefix. Separate records limit the impact of a leaked or misconfigured credential and make provider-side audit logs easier to interpret. A single broader credential may be convenient, but convenience is not evidence that both directions require the same permissions.

### When should I use SFTP or FTP instead of object storage?

Use a native integration when it matches the provider and the workflow should avoid proxying file bytes through application servers. Choose SFTP when an existing partner contract requires SSH file transfer or a server filesystem. Use FTP only for compatibility with an endpoint that cannot offer a stronger supported route, then constrain the account, destination path, and network exposure as much as the server permits.

### How should my application track files across providers?

Store the Assembly ID, provider-independent asset ID, destination key or path, and the intended version in your database. Treat notifications as retryable events and make completion handling idempotent. For a large import, persist page or batch progress and reconcile expected assets against completed exports. Provider folder names and sharing URLs are useful presentation data, but they are fragile primary identifiers.

### Can I switch providers by changing only the Robot name?

Not safely without reviewing the contract. The Assembly graph may remain similar, but credentials, bucket or container fields, path rules, access settings, result URL fields, recursion, and pagination can differ. Build a provider adapter in trusted application code or maintain reviewed Templates per destination. Do not allow a browser to select an arbitrary Robot or inject storage credentials into otherwise trusted Instructions.

## Build the workflow

Move from the concept to a tested Assembly with Robot documentation and working demos.

* [Protect storage credentials](/docs/topics/template-credentials.md)
* [Browse import and store Robots](/docs/robots.md)
* [Connect workflow Steps](/docs/topics/assembly-instructions.md)
* [Reconcile completed exports](/docs/topics/webhooks.md)
* [Understand temporary result retention](/docs/faq/temporary-purge-sooner.md)
* [Read the API documentation](/docs.md)
* [Explore working demos](/demos.md)
* [Create a free workspace](/c/signup/)

Platforms and integrations

## Continue with related guides

* [File uploads, image optimization, and your own S3 bucket](/guides/file-uploads-image-optimization-s3.md)\
  Combine resumable browser uploads, image optimization, customer-owned Amazon S3 storage, and on-demand delivery without operating separate media services.
* [Customizable media processing workflows with Transloadit](/guides/customizable-media-processing-workflows.md)\
  Design a reusable Template with validation, variables, parallel derivatives, secure storage, and observable completion.
* [Integrate Transloadit in five minutes](/guides/transloadit-five-minute-integration.md)\
  Install the Node SDK, resize one image, and inspect a real Assembly result in about five minutes.
* [Four pillars of digital transformation in retail](/guides/retail-digital-transformation-pillars.md)\
  Connect customer experience, operations, data, and platform modernization through a practical retail media layer.
* [Magento media optimization for technical SEO](/guides/magento-media-seo.md)\
  Improve Magento media performance and image search hygiene as part of a broader technical SEO program.
* [Media uploads for Angular commerce applications](/guides/angular-ecommerce-media-uploads.md)\
  Design an Angular commerce upload and media workflow with resumability, signed Templates, and asynchronous results.
