Storage Patterns
Storage is for files and blobs.
Use storage disks for uploads, generated files, public assets, private files, and remote object stores. Use the database for relational state and metadata.
When To Use Storage
| Question | Guidance |
|---|---|
| Use this when | The workflow produces or consumes files, blobs, exports, uploads, or remote objects. |
| Avoid this when | The data needs relational querying, ownership rules, authorization state, or transactional updates by itself. |
| Start with | Local or memory storage for local development and tests. |
| Upgrade to | Object storage or a remote filesystem when more than one host or runtime needs the same files. |
Generated Disks
Generated Apps expose default and named disks:
app.Storage()
app.Storage().Public()
app.Storage().Uploads()Named disks come from environment variables:
STORAGE_SUPPORTED_DRIVERS=local,s3
STORAGE_DRIVER=local
STORAGE_PUBLIC_DRIVER=local
STORAGE_UPLOADS_DRIVER=s3
STORAGE_UPLOADS_BUCKET=my-app-uploads
STORAGE_UPLOADS_REGION=us-east-1After adding or renaming named disks, use the normal build path:
forj buildDev Loop
During forj dev, the generated build watcher normally runs forj build for you.
Use focused generation only when you intentionally want to refresh storage code without a full build:
forj generate --storageGood Uses
Storage is a good fit for:
- user uploads
- generated exports
- public assets
- private documents
- object storage
- remote filesystem integration
Store metadata, ownership, and lifecycle rules in the database when those are part of business state.
Choosing Storage Drivers
Use this default path:
| Need | Driver Shape |
|---|---|
| Local development and tests | local or memory |
| One host owns the files | local |
| Multiple hosts need the same files | object storage or remote filesystem |
| Public asset delivery | object storage or CDN-backed disk |
| Temporary distributed blob storage | Redis only with explicit size and durability limits |
Use local storage until deployment topology makes that wrong. If API and workers run on different hosts, local disk paths stop being a shared contract.
Path Discipline
Keep storage paths stable and scoped.
Prefer:
users/{userID}/avatars/current.png
reports/{reportID}/exports/latest.csvAvoid raw user filenames as trusted paths. Normalize and validate paths at the boundary that accepts user input.
Local and Production Drivers
Use local or memory storage for local development and tests.
Use S3, GCS, FTP, SFTP, Dropbox, rclone, Redis, or other supported drivers when production requirements need shared or remote storage.
Use Storage for the full package-level driver matrix.
Consistency With Database
Database transactions do not automatically include storage writes.
When a workflow creates both database rows and storage objects, decide:
- which write happens first
- what cleanup happens after failure
- whether retries are safe
- whether missing blobs are recoverable
Common Mistakes
Common mistakes
- Do not store relational source-of-truth data in object paths alone.
- Do not hardcode local filesystem paths in business services.
- Do not import storage driver packages into normal application logic.
- Do not assume every driver supports every capability, such as temporary URLs.
- Do not skip path normalization for user-controlled filenames.
Next Steps
- Named Resources explains named disks.
- Driver Selection explains backend choices.
- Storage covers standalone package behavior.
