Adapters
Connect Tulip Storage to an object storage provider through a storage adapter.
Tulip Storage talks to object storage through adapters. The Storage service owns the database lifecycle for assets, while the adapter is responsible for talking to the provider itself.
In practice, that means the adapter handles operations such as:
- reading objects
- generating signed read URLs
- reading object metadata
- uploading objects directly from the server
- generating signed upload URLs
- deleting one or more objects
Your app passes one adapter into Storage.init():
import { Storage, storageS3Adapter } from "@tulip-systems/core/storage/server";
export const storage = Storage.init({
db,
adapter: storageS3Adapter({
bucketName: env.S3_BUCKET,
region: "auto",
endpoint: env.S3_ENDPOINT,
credentials: {
accessKeyId: env.S3_ACCESS_KEY_ID,
secretAccessKey: env.S3_SECRET_ACCESS_KEY,
},
}),
});Current adapter support
Tulip currently ships with one built-in storage adapter:
s3
This page is structured so more providers can be documented later without changing the overall storage setup flow.
S3
Use storageS3Adapter() when your files live in AWS S3 or an S3-compatible provider.
import { storageS3Adapter } from "@tulip-systems/core/storage/server";
const adapter = storageS3Adapter({
bucketName: env.S3_BUCKET,
region: "auto",
endpoint: env.S3_ENDPOINT,
credentials: {
accessKeyId: env.S3_ACCESS_KEY_ID,
secretAccessKey: env.S3_SECRET_ACCESS_KEY,
},
});Configuration
The S3 adapter requires:
bucketName, the bucket Tulip should read from and write to- any standard AWS
S3Clientoptions you want to pass through
The most common options are:
regionendpointcredentials.accessKeyIdcredentials.secretAccessKey
Because the adapter forwards its config into the AWS SDK S3Client, you can also pass other supported client options when needed.
Environment variables
The examples in demo-spark and demo-code use these server env vars:
S3_BUCKET="my-app-uploads"
S3_ENDPOINT="https://<your-s3-endpoint>"
S3_ACCESS_KEY_ID="..."
S3_SECRET_ACCESS_KEY="..."You will usually also set a region, either directly in the adapter config or through your provider's recommended setup.
AWS S3 and S3-compatible providers
The adapter works with AWS S3, but it is not limited to AWS. If your provider exposes an S3-compatible API, you can usually point Tulip at it through endpoint and the matching credentials.
That makes the adapter a good fit for setups such as:
- AWS S3
- Cloudflare R2
- MinIO
- other S3-compatible object stores
The exact region, endpoint, and credential values depend on your provider.
What the S3 adapter enables
When used with Storage, the S3 adapter powers both upload flows supported by Tulip:
- server-side uploads with
storage.upload() - browser uploads with
presign -> PUT -> confirm
It also handles file delivery operations such as:
- resolving object metadata
- creating signed read URLs for
/api/storage/files/:id - deleting one object or many objects during cleanup and purge flows
Common notes
- Make sure the target bucket already exists.
- Keep uploaded objects private by default unless your app explicitly wants public visibility.
- Prefer serving files through
getAssetURL()and the Tulip route handler instead of storing raw provider URLs in your UI. - If you use an S3-compatible provider, validate its required
endpointand signing expectations first.
Once your adapter is configured, continue with /docs/storage/setup to wire it into Storage, your app context, and your routes.