Skip to content

Go to the docs contents

Object storage (S3)

S3 buckets in France for your app’s files: images, exports, documents. They’re encrypted and versioned, and your app receives a key that works only for them.

Updated November 9, 2026.

View as Markdown

You, to your agent: Add storage for the visit photos.

What your agent writes

Your agent writes it in while.yaml, at the root of your app:

while.yaml
buckets:
  - name: uploads

What your app receives

Your app receives these environment variables at every deployment:

VariableWhat it holds
S3_ENDPOINTThe S3 endpoint your app reaches.
S3_REGIONThe S3 region.
AWS_REGIONThe same, for the AWS SDKs.
AWS_ENDPOINT_URL_S3The S3 endpoint, for the AWS SDKs.
S3_BUCKET_UPLOADSThe name of the uploads bucket.
S3_BUCKETThe name of the first bucket.
AWS_ACCESS_KEY_IDThe access key, limited to the environment’s buckets.
AWS_SECRET_ACCESS_KEYIts secret.
S3_ACCESS_KEY_IDThe same key, under another name.
S3_SECRET_ACCESS_KEYIts secret.
S3_ENDPOINT_PUBLICThe public S3 endpoint, for a presigned URL that a browser opens.

When to use it

For files (images, exports, documents), rather than in the database.

How it works

Each declared S3 bucket is created in France, encrypted and versioned. The app receives the S3 endpoint, the name of its buckets and a key limited to its environment’s buckets.

What to know

An app with closed egress (the default) reaches its buckets through while’s S3 relay (S3_ENDPOINT, in the cluster). Through the relay, the key received is only valid for the environment’s buckets, and only from its pods. To read a bucket from a workstation, without a key, your agent uses the read_bucket tool.

A presigned URL for a browser is made on S3_ENDPOINT_PUBLIC, in path style (forcePathStyle), and the app’s addresses are allowed on it (CORS). For another origin, declare buckets: [{ name, cors: [https://…] }]. The public address takes presigned URLs to read or send an object (GET, HEAD, PUT, 5 GB at most), and presigned POST forms (createPresignedPost): the relay checks the policy (signature, expiration, bucket, key or its prefix, Content-Type, x-amz-meta-*) and counts content-length-range during the upload. A URL that signs content-length enforces the size: the relay checks the signature with it and passes Content-Length on as is; any other length is refused.

The bucket is created at deployment: it is a billed resource, approved like a database, and public: true (anonymous read) requires approval too. A replaced or deleted version of an object is kept 30 days. A preview has its own buckets, empty: nothing is copied. Buckets go with their environment, emptied, versions included. Object locking in compliance mode is not offered.

Pricing

These prices are the same on every plan, excluding VAT:

ResourcePriceDetails
Object storage€0.25 per 10 GiB·monthrequests included

Your agent’s MCP tools

Your agent handles it with the get_app_status and read_bucket tools.

Guides

Connect your agent, it takes care of the rest

To paste into your agent

Read while.sh/agents, then deploy my app with while.

Copy the instructions

No account needed to try: your app is live right away. To keep it, sign in.

A project for your company? Talk to the team: hello@while.sh