01 Use case · Product teams

Ship files as a feature,
not a storage project.

Every product ends up handling uploads, attachments, documents and exports. Uplint gives your team a complete file layer behind one API — so the feature ships this sprint, and the cloud decisions never end up in product code.

One call to upload Signed URLs to serve Change storage without a rewrite
YOUR PRODUCTONE CALLDECIDED BY POLICYPNGProfile photoavatar.png · 1.2 MBavatarsIMGTicket attachmentscreen.jpg · 640 KBattachmentsPDFSigned contractmsa.pdf · 3.8 MBdocumentsCSVMonthly exportusage-aug.csv · 9 MBexportsuuplint.filesawait uplint.files.upload({file, storage: "…", metadata})file_8Kx92mfile_3Qa17vfile_Zp40dmfile_c9Lm2eS3AWS S3ap-south-1productionAZAzure Blobwesteuropeeu-customersR2Cloudflare R2auto-regionarchivePNGfile_8Kx92mIMGfile_3Qa17vPDFfile_Zp40dmCSVfile_c9Lm2e
02 Every product has files

Every feature has files.
Handle them once.

Each of these used to mean another upload path, another bucket convention, another cleanup job. With Uplint every surface is the same call — only the target changes.

acme.app / settings / profileavatars
EK↑
Display nameEkansh
WorkspaceAcme Support
Upload new photoRemove
THE CALLsame for every surface
await uplint.files.upload({file,storage: "avatars",metadata: { user: "usr_91k" }});
03 What your sprint stops carrying

The tickets that never
reach your board.

A file layer is a dozen small pieces of infrastructure that every product rebuilds. Take them out of the sprint and what is left is the work your users actually see.

Sprint 14 · Attachments, avatars, exports
Feature Infrastructure
Without Uplint11 tickets
Upload APISigned URLsMetadataBucket configEU migrationCredentialsAudit logAttach filesPhoto cropUsage exportContracts
With Uplint4 tickets
Attach filesPhoto cropUsage exportContracts
MOVED OUT OF THE SPRINT7 infrastructure tickets → the API you already call
Upload endpoint, size and type validationPOST /v1/files
Presigned URL service per provider/v1/files/:id/url
File metadata table and bucket path schemefile record
Per-customer bucket and region configurationrouting policy
Migration when a customer needs an EU region/v1/files/:id/move
Storage credential rotation and scopingstorage connection
Audit log of who accessed which fileevents
04 Start simple, grow on demand

One call at launch.
The same call at scale.

Start with one bucket. Add regions, providers and customer-owned storage when a customer asks — in configuration, without touching the code that ships features.

  1. 01Launch

    One bucket, one region.

    Connect the S3 bucket you already have. Every upload lands there.

    production → S3 · ap-south-1
    product code changed: none
  2. 02First EU customer

    Add a routing policy.

    EU accounts go to Azure in Frankfurt. Everyone else stays where they are.

    eu-customers → Azure · westeurope
    product code changed: none
  3. 03Enterprise deal

    Connect their bucket.

    The customer issues scoped credentials. Their files never leave their account.

    acme-corp → S3 · customer-owned
    product code changed: none
  4. 04Cost review

    Move cold files to R2.

    Archive files move provider. IDs stay the same, so every link keeps working.

    archive → R2 · move
    product code changed: none
05 In your stack

A few lines server-side.
Nothing client-side.

Upload from the route you already have, store the file ID next to the record, and hand the client a signed URL when it needs to render or download.

  • Node SDK, or plain HTTPS from any language
  • The file ID is one string column next to the record
  • Buckets stay private; the client only ever sees a signed URL
tickets/attach.tsserver route
const file = await uplint.files.upload({file: req.body,storage: "attachments",metadata: { ticket: ticket.id, uploadedBy: user.id }});await db.attachments.insert({ ticketId: ticket.id, fileId: file.id });
tickets/[id].tsxwhen it renders
const { url } = await uplint.files.url(attachment.fileId, { expires: 300 });// signed against whichever provider holds it — today S3, next year anything
06 Questions

Straight answers.

No. Store the file ID as a string on the record it belongs to — the ticket, the user, the invoice. Everything else about the file — size, type, metadata, current location — lives in Uplint’s record and is one GET away.

FILES, SHIPPED THIS SPRINT.

Your next feature has files.
Ship it with Uplint.

Connect a bucket, create a key, and make the upload call. The storage decisions can wait until a customer asks.