BlogFile storage

How to add file uploads to your app.

Files saved to your app's disk disappear on the next deploy. A private S3 bucket keeps them, and your agent creates it for you.

How the Agent API works
  • A private bucketOne per app, in Singapore
  • A key for one bucketIt reaches nothing else
  • Browsers upload directlyThrough a presigned URL
  • Disk is temporaryFlagged before it builds

The short answer

To add file uploads, tell your connected coding agent to create a bucket and save uploads to it. Antideploy creates a private S3 bucket for your app, writes its variables into your .env without printing the key, and gives the running app the same variables. Any S3 client works with it. Never save uploads to the app's own disk, because the disk is replaced on every deploy.

Say this to your coding agent

Add file uploads to this project and store the files in a bucket.

If your agent is not connected yet, paste this first: Set this project up to deploy on Antideploy. Fetch https://antideploy.com/agent.md and follow it.

Why not the disk

A container is replaced on every deploy and its disk goes with it. A user's avatar saved with multer or fs.writeFile is gone after the next deploy, and nothing will error. Antideploy flags code that saves uploads to disk before it builds anything. A bucket is not replaced, and it belongs to your application.

What your agent does

  1. It creates the bucket before it writes the upload code

    So the upload is written and tested against the real thing. Asking twice returns the same bucket.

  2. It writes the variables into your .env

    The key goes into a file through a redirect that never prints it. The deploy that follows gives the running app the same variables.

  3. Your code uses any S3 client

    The AWS SDKs and boto3 read the AWS_* variables from the environment, so code that reads them and sets nothing else already works.

A project that uses an S3 client and brought no key of its own gets a bucket at its first deploy, even without asking.

Upload straight from the browser

Have your server return a presigned PUT URL. The browser sends the file straight to the bucket, without passing through your app. Browsers on any origin may call the bucket, and every request still needs the key or a link signed with it.

Node
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const s3 = new S3Client({ forcePathStyle: true });
const url = await getSignedUrl(
  s3,
  new PutObjectCommand({ Bucket: process.env.BUCKET_NAME, Key: "avatars/maya.webp" }),
  { expiresIn: 300 },
);
// hand url to the browser, which PUTs the file straight to the bucket

# Python
import os, boto3

s3 = boto3.client("s3")
s3.upload_file("avatar.webp", os.environ["BUCKET_NAME"], "avatars/maya.webp")

Showing a file to a visitor

The bucket is private, so there is no public URL. To show a file, serve it through your app, or hand the visitor a signed link that expires.

What you get

  • One private bucket per app, on Neon Object Storage in Singapore
  • A key that reaches that bucket and nothing else
  • Storage is not metered or capped today
  • Buckets per account: 1 on Free, 2 on Go, 3 on Pro and 5 on Scale

01Before you commit

Here's where it stops.

A platform that only tells you what it is good at is one you find the edges of in production. These are the ones to know before your first deploy.

  1. The disk forgets

    Anything written to local disk is gone on the next deploy. Apps that speak S3 get a bucket instead.

  2. One region

    Everything runs in Singapore, with the database beside the app. Users far from Asia will see slower responses.

02Questions

Upload questions, answered.

Anything else? Write to us and a person answers.

support@antideploy.com
Which S3 clients work?

Any S3 client. Current AWS SDKs and boto3 choose path-style addressing by themselves for this bucket. In new JavaScript code, set forcePathStyle: true anyway.

Can I use Cloudinary or UploadThing instead?

Yes. Antideploy only creates a bucket for code that uses an S3 client and brought no key of its own, and a key you set yourself is never replaced.

Should I copy the variables into my secrets?

No. The platform sets them in the running app, and a copy could shadow the real ones.

What if I reach my bucket limit?

Creating another answers with a plan-limit error, and your agent tells you. Nothing already created is affected. You can delete an application you no longer need, or move to a plan with more.

Is there a public CDN?

No. Every object is private, and there is no built-in CDN.

Deploy something. Start with one sentence.

Paste one sentence into your coding agent, click Approve once, and get a live link. No card, no trial clock.

Start from GitHub or a folder
Prompt copied Paste it into Claude Code, Codex or Cursor and press Enter.