Dibbla Docs Get started Guides Workflows Changelog
Open Console
Guides

Storing files

Managed S3-compatible buckets — how your app gets credentials it never has to handle, what the quota does when you hit it, and how to rotate a key without taking the app down.

Apps that accept uploads, generate reports or cache artifacts need somewhere to put files that survives a redeploy. A container’s filesystem does not: it is replaced every time you ship. Dibbla’s answer is a managed bucket — S3-compatible object storage, provisioned the same way a database is.

dibbla storage create my-uploads --size 25Gi

That one command does three things, and the second is the one worth understanding.

Your app never handles a key

Creating a bucket mints a credential scoped by policy to that bucket alone and injects it as four secrets:

STORAGE_MY_UPLOADS_ENDPOINT
STORAGE_MY_UPLOADS_BUCKET
STORAGE_MY_UPLOADS_ACCESS_KEY_ID
STORAGE_MY_UPLOADS_SECRET_ACCESS_KEY

They arrive in your app’s environment on the next deploy. Nothing gets pasted into a config file, committed by accident, or shared between apps — and if that credential ever leaks, it opens exactly one bucket. It cannot read, write or even list any other bucket on the platform.

The <NAME> part is the bucket name uppercased with hyphens turned into underscores, because bucket names allow hyphens and environment variable names do not. my-uploads becomes STORAGE_MY_UPLOADS_*.

import os, boto3

s3 = boto3.client(
    "s3",
    endpoint_url=os.environ["STORAGE_MY_UPLOADS_ENDPOINT"],
    aws_access_key_id=os.environ["STORAGE_MY_UPLOADS_ACCESS_KEY_ID"],
    aws_secret_access_key=os.environ["STORAGE_MY_UPLOADS_SECRET_ACCESS_KEY"],
    config=boto3.session.Config(s3={"addressing_style": "path"}),
)

s3.upload_fileobj(file, os.environ["STORAGE_MY_UPLOADS_BUCKET"], "invoices/2026-08.pdf")

Any S3 SDK works — boto3, the AWS SDK for JavaScript, minio-go, whatever your language offers. Use path-style addressing; the platform’s endpoint does not serve virtual-host-style bucket URLs.

The quota is hard

--size is not advice. When a bucket is full, uploads fail with a quota error rather than quietly succeeding, so pick a number that reflects real usage:

dibbla storage create my-uploads --size 25Gi
dibbla storage info      # size, object count and quota for every bucket

For data that ages out on its own — logs, exports, temporary renders — let the platform clean up instead of growing the quota:

dibbla storage create logs-archive --size 5Gi --expire-days 90

Usage figures come from the store’s accounting pass, so a file uploaded seconds ago may not be reflected in storage info yet. The quota itself is enforced immediately.

Rotating a credential without an outage

Rotation replaces the key, and the old one dies the moment it does:

dibbla storage rotate my-uploads

Your running pods read secrets from the environment when they start, so a new key does not reach a running app on its own. That is why rotate restarts the bound deployment’s services for you — otherwise “rotate” would just be an outage spelled differently. If you would rather control the restart yourself:

dibbla storage rotate my-uploads --no-restart
dibbla apps restart my-app --service web   # until you do this, the app holds a dead key

Buckets belong to the organization

Like databases, a bucket is org-scoped rather than owned by one app, so several apps can share one. If a bucket is really one app’s business, scope its secrets:

dibbla storage create my-uploads --deployment my-app

Then only that deployment gets the four variables.

Deleting takes everything with it

dibbla storage delete my-uploads          # refused while the bucket has objects
dibbla storage delete my-uploads --force  # bucket, contents, credential and secrets

Delete removes the bucket, its scoped credential and its injected secrets together — no orphaned environment variables pointing at storage that no longer exists.

From the console

Everything above is also in the console under Storage: create with a name and quota, watch usage against it, rotate, delete. The CLI and the console drive the same API, so use whichever fits the moment.

Naming rules

3–48 characters, lowercase letters, digits and hyphens, starting and ending with a letter or digit. Uppercase and underscores are rejected, and workflows, files, cnpg-backups and workflow-artifacts are reserved by the platform.

Self-hosting

Managed buckets are on whenever your install has object storage configured — the bundled MinIO or an external S3-compatible store. See self-hosting with Helm for the values involved. Where it is switched off, the commands answer STORAGE_NOT_CONFIGURED and the console’s Storage tab says so in plain language.