Skip to main content

Object Storage

Kuploy provides managed object storage — S3-compatible buckets for the files your app produces: user uploads, images, video, generated assets, exports. Like a database, a bucket is a resource you create in your project and connect to your app; the platform provisions it and injects the credentials for you, so you never paste keys.

When to use it

Reach for a bucket whenever your app stores files that must outlive a redeploy and be shared across replicas — anything you'd otherwise put on local disk (which is ephemeral and per-pod). Because it speaks the S3 API, any S3 client works: boto3, the AWS SDKs, aws-cli, mc, rclone, and most frameworks' file-storage adapters.

Creating a bucket

  1. Navigate to your project's environment.
  2. Click Create ServiceBucket (under the Storage category).
  3. Configure:
    • Name — a label for the bucket (e.g. media).
    • Quota (GiB) — the maximum the bucket may hold. 0 means unlimited.
  4. Click Create, then Provision.

Provisioning takes a few seconds. When it's done, the bucket's page shows its endpoint, bucket name, region, access key, and secret key (the secret is hidden until you reveal it, and every value has a copy button).

Connecting a bucket to your app

Don't copy the credentials by hand — connect the bucket to your service and Kuploy injects them as environment variables. In a stack, draw a connection from the bucket to your app and map each field to the env var your app expects:

Bucket fieldWhat it isTypical env var
endpointS3 API endpoint (private to your cluster)S3_ENDPOINT / AWS_ENDPOINT_URL
bucketThe provisioned bucket nameS3_BUCKET
accessKeyAccess key IDAWS_ACCESS_KEY_ID
secretKeySecret access keyAWS_SECRET_ACCESS_KEY
regionRegion (arbitrary but required by most SDKs)AWS_REGION

The resolved values land in your app's Environment tab inside a managed block (marked do not edit) and update automatically — if you rotate or re-provision the bucket, connected apps pick up the new values on their next deploy.

tip

The connection is one-directional and server-side: credentials are resolved into the consumer's environment at deploy time and never exposed to the browser. Keep them server-side in your app too (don't ship them to client-side code).

Example (Python / boto3)

With the env vars above injected, no credentials appear in your code:

import boto3, os

s3 = boto3.client(
"s3",
endpoint_url=os.environ["S3_ENDPOINT"],
aws_access_key_id=os.environ["AWS_ACCESS_KEY_ID"],
aws_secret_access_key=os.environ["AWS_SECRET_ACCESS_KEY"],
region_name=os.environ["AWS_REGION"],
)
s3.upload_file("thumbnail.png", os.environ["S3_BUCKET"], "courses/1/thumbnail.png")

Quotas

Each bucket has its own capacity limit. When a bucket reaches its quota, further uploads to that bucket fail with a quota error — other buckets and services are unaffected. Raise a bucket's quota from its settings, or set 0 for unlimited when you create it.

Monitoring usage

Once a bucket is provisioned, its detail page shows a Storage usage panel with live figures read straight from the storage backend:

  • Objects — how many objects the bucket holds.
  • Total size — the bytes stored.
  • Quota fill — a bar showing how full the bucket is against its quota (hidden when the quota is 0 / unlimited).
  • A Reachable / Unreachable badge for the shared storage backend — if it can't be reached, the badge carries the reason instead of silently showing zeros.

For the whole picture across every bucket in your organization, open Settings → Organization storage (organization admins). It aggregates total objects, total size, and summed quota, with a per-bucket breakdown and each bucket's reachability — a quick way to see where your storage is going without opening each bucket in turn.

Access & isolation

Every bucket gets its own dedicated access key, scoped to that bucket alone — a bucket's credentials cannot read or write any other bucket. The endpoint is reachable only from within your cluster (your other services), not the public internet, so uploaded objects are served through your app rather than exposed directly.

Deleting a bucket

Delete a bucket from its detail page (you'll be asked to type its name to confirm). This permanently removes the bucket, everything stored in it, and its access key. There is no undo — download anything you need first.

Best practices

  1. Connect, don't paste — wire the bucket to your app so credentials inject automatically and rotate cleanly.
  2. One bucket per concern — separate, say, public media from private exports; each gets its own scoped key and quota.
  3. Set a quota — cap growth so one runaway feature can't fill the bucket unexpectedly.
  4. Keep keys server-side — never expose the injected AWS_* vars to browser code; serve or proxy files through your app.
  5. Store the path, not the file — keep object keys/paths in your database and stream from the bucket on demand.