@talosjs/storage component is a multi-backend file storage layer. Every backend implements the same IStorage interface (put, getFile, getAsJson, delete, list, and more), so you can start on the local filesystem and move to Cloudflare R2 or Bunny while your calling code stays the same. Files are organized into buckets, and the S3-compatible backends share one abstract Storage base class.
One interface across backends
Filesystem, Cloudflare R2, and Bunny all implementIStorage, so you can swap backends without touching callers. Files live under buckets: setBucket() and getBucket() set and read the active one, and you can list or clear a whole bucket in a single call. put() accepts strings, ArrayBufferView, ArrayBuffer, SharedArrayBuffer, Blob, Request/Response, and BunFile/S3File, and you read a file back however you need it: as JSON, as an ArrayBuffer, as a stream, or written straight to disk with getFile(). For bulk uploads, putDir() walks a local directory recursively with an optional regex filter. Register a storage class with a decorator and resolve it from the container.
How it works
You pick (or implement) a backend and register it. Reads and writes go through theIStorage methods; the backend handles the transport, bucketing, and content conversion.
The three packaged backends differ in where files live, not in how you call them:
FilesystemStorage and CloudflareStorage extend the shared Storage base class and talk to an S3 client under the hood. BunnyStorage implements IStorage directly against the Bunny Storage SDK.
Environment variables
Usage
The API is the same regardless of backend.Decorator and usage
@decorator.storage()
Registers a storage class with the container. It accepts an optional scope (defaults to singleton). Use it to register a packaged backend under your own name, or a custom backend that extends Storage or implements IStorage.
Exceptions
The component throwsStorageException when a backend is misconfigured or an operation fails. It carries a machine-readable key, a human-readable message, and a data object.
Storing files cleanly
CallsetBucket() before any read or write, since FilesystemStorage throws STORAGE_BUCKET_REQUIRED otherwise. Group related objects under stable prefixes like avatars/123.png so list() and clearBucket() stay predictable. For anything large, stream with getAsStream() (and putDir/putFile for local sources) instead of loading whole files into memory, and pass a filter regex to putDir() so you only ship the files you mean to.
Choose the backend by environment: filesystem for local and dev, Cloudflare R2 or Bunny for production, with the same code either way. Reads throw FILE_NOT_FOUND (or STORAGE_DOWNLOAD_FAILED) when an object is absent, so catch StorageException and branch on error.key. In a custom backend, keep that key constant and put the variable detail in data.
CLI command
Scaffold a storage adapter and its test file with the generator. It writes the class undermodules/<module>/src/storage/<Name>Storage.ts and installs @talosjs/storage if it is missing.
The generated class extends
Storage as an S3-compatible adapter, ready for you to set the bucket and confirm its credentials:
Use with Claude and Codex
The generator ships a matchingstorage:create skill. It runs the scaffold, then guides your AI agent through completing the adapter: setting the bucket, wiring the credential env vars, and finishing the test file. Initialize the skills once for your agent.
- Claude
- Codex
Prompt
storage:create --name=Upload, then sets the bucket and credential env vars on the generated Storage subclass.