Buckets are S3-compatible object storage. You create and browse them under Storage → Buckets: upload files, inspect objects, and choose at creation whether the bucket is public (anyone can read its objects) and whether it keeps versions. Attach a bucket to an app and the app receives scoped credentials to read and write it with any S3 SDK.
Attaching a bucket to an app#
Buckets are one kind of app dependency. On the app's Resources tab, choose Add dependency → Bucket, then:
- Attach an existing bucket, or create a new one by name.
- Choose the Access: Read & write or Read only.
- Check the variable names. They default to the
S3_*names below; type a prefix such asASSETS_S3_into Fill all names from a prefix to rename all six at once.
The dialog shows every variable the app will receive before you submit. Attaching restarts the app so it picks up the new variables.
What your app receives#
| Variable | Value |
|---|---|
S3_BUCKET | The bucket's storage name |
S3_ENDPOINT | The object storage address, reachable from your app only |
S3_REGION | The region S3 clients sign with |
S3_FORCE_PATH_STYLE | true |
S3_ACCESS_KEY_ID | The app's access key, a plain variable |
S3_SECRET_ACCESS_KEY | The app's secret key, a write-only secret variable |
These are managed variables: renamable under Edit, but not editable in the environment editor, the API or the CLI.
Buckets use path-style addressing (endpoint/bucket/key). Configure your SDK to force path style, or requests go to a hostname that doesn't exist.
The credential belongs to the app, not the bucket: every bucket an app attaches uses the same key pair. A second attachment can reuse the same credential variable names or use its own prefix.
SDK examples#
AWS SDK for JavaScript v3:
import { S3Client } from "@aws-sdk/client-s3";
const s3 = new S3Client({
endpoint: process.env.S3_ENDPOINT,
region: process.env.S3_REGION,
forcePathStyle: process.env.S3_FORCE_PATH_STYLE === "true",
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
},
});
Elixir with ExAws, in your app's runtime.exs (ExAws already uses path-style addressing against a custom host):
endpoint = URI.parse(System.fetch_env!("S3_ENDPOINT"))
config :ex_aws,
access_key_id: System.fetch_env!("S3_ACCESS_KEY_ID"),
secret_access_key: System.fetch_env!("S3_SECRET_ACCESS_KEY"),
region: System.fetch_env!("S3_REGION")
config :ex_aws, :s3,
scheme: "#{endpoint.scheme}://",
host: endpoint.host,
port: endpoint.port
From outside the platform#
The S3_ENDPOINT your app receives only works from inside Nimbus Land. To reach a bucket from your laptop, CI or a desktop S3 client, use the Connecting from outside section on the bucket's page. It shows:
- Endpoint: the public object storage endpoint.
- Region: the region to put in your client's configuration.
- Addressing: path-style; turn on "force path style" in your client.
- Credentials: the access key of an app the bucket is attached to. The same keys work from outside as from the app. The key ID is on that app's Resources tab; the secret is write-only, so print it from inside the app if you need it:
nimbus run my-app -- sh -c 'echo $S3_ACCESS_KEY_ID $S3_SECRET_ACCESS_KEY'
A bucket attached to no app has no credentials yet. Attaching it to an app is how keys are issued.
Access modes#
- Read & write: list, get, put and delete objects, and multipart uploads.
- Read only: list and get objects.
Neither mode lets the app change the bucket itself. Its access policy, versioning and public setting are managed in the console only.
Sharing a bucket across apps#
You can attach the same bucket to as many apps in your organization as you like. Each app has its own credential, and detaching or deleting one app never affects another's access. The bucket page's Connected apps section lists every attached app with its access mode and a Detach button.
Versioning#
Versioning keeps the previous contents of an object whenever it is overwritten or deleted, so a bad upload or an accidental delete can be undone. It is off by default. Tick Enable versioning when you create a bucket, or use the Versioning switch on an existing bucket's page.
- On: every overwrite keeps the old version, and Delete hides the object behind a delete marker instead of removing it.
- Suspended (switched off after being on): new uploads replace objects without keeping a version, but versions already kept stay until you delete them.
- Off (never turned on): overwrites and deletes cannot be undone.
On a versioned bucket, switch on Include deleted and previous versions above the objects list to see every version, newest first. Then:
- Restore this version copies that version back as the current one. Nothing is removed, so a restore can itself be undone. It works only while versioning is on.
- Undelete (on a deleted object) removes the delete marker, so the latest version is current again.
- Download on any version downloads exactly that version.
- Delete permanently (all versions) removes every version of the object. This is the only way to remove kept versions today; they don't expire on their own.
A versioned bucket's Size includes every kept version, and previous versions are billed like any other stored data.
Versioning protects against mistakes, not against loss of the storage itself. Versions live in the same bucket, and deleting the bucket, or deleting a version through the S3 API with a read and write key, removes it for good. Keep your own copy of anything irreplaceable.
Rotating keys#
Open Edit on any bucket entry in the app's Dependencies panel and choose Rotate keys under Credentials. A new key pair is issued, every attachment's key variables are rewritten under the names they use, and the app restarts. The old key stops working immediately. Because the key is shared, rotating it affects every bucket attached to that app.
Detaching and deleting#
- Detach removes the variables that attachment owned. Detaching the app's last bucket also revokes its key; attaching a bucket later issues a new one.
- A bucket with connected apps cannot be deleted: detach every app first.
- Deleting an app revokes its key and removes its access from every bucket it was attached to. Other apps sharing those buckets are unaffected.
- Deleting a bucket asks you to type its name and cannot be undone.
Pricing#
Bucket storage costs $0.10 CAD per GB-month on any plan, for everything a bucket holds, previous versions included. It is measured once a day, so a bucket that holds 10 GB for half a month costs about $0.50. Downloads are billed separately as bandwidth, below.
Storage limit#
Each organization can keep up to 250 GB in buckets on Starter and 1 TB on Business, counted across all its buckets, previous versions included. Billing managers are emailed when you reach 80%, and the Storage page shows usage against the limit. At the limit, new uploads are refused with an access-denied error; reading, downloading and deleting keep working, so you can free space. Uploading works again once usage is below the limit. To raise the limit, contact support.
Downloads and bandwidth#
Downloads through the public storage endpoint count toward your organization's bandwidth: objects in a public bucket fetched by anyone, and downloads through a shared (signed) link. Each is attributed to its bucket. Your apps reading and writing their attached buckets use the platform's internal endpoint, so that traffic is free, and so are uploads.
Limits#
- No storage quota per app or per bucket; the limit is per organization (see Storage limit).
- Access is to the whole bucket. You can't limit an app to a prefix within it.
- Attaching and detaching buckets is done in the console.
nimbus bucketslists your organization's buckets, andGET /api/v1/bucketsreturns them. - Variable changes reach the app on its next restart, which attaching, detaching and rotating start for you.
Also available as Markdown.