“Our data can’t leave the EU. Not the backups either.”
Compliance lead, EU customer{tenant: "acme",provider: "azure",region: "westeurope",}Every upload for acme lands in Frankfurt. Nothing else in your product changes.
Some customers need their files in the EU. Some need their own bucket. Some just signed and need to be live by Monday. Uplint turns each of those into a routing policy — a row in a table, not a branch in your code.
Each of these once meant a special deployment, a hand-run migration, or a “no”. With Uplint each one is a policy entry — and the product stays one product.
“Our data can’t leave the EU. Not the backups either.”
Compliance lead, EU customer{tenant: "acme",provider: "azure",region: "westeurope",}Every upload for acme lands in Frankfurt. Nothing else in your product changes.
“Files have to sit in a bucket we own and can audit ourselves.”
Security team, enterprise deal{tenant: "globex",connection: "globex-s3",bucket: "globex-files",}They issue scoped credentials; Uplint writes into their account and keeps only the record.
“We’re a Google Cloud shop. Can this run on GCS?”
Platform engineer, procurement{tenant: "umbrella",provider: "gcs",region: "asia-south1",}Yes — as one policy entry, not a second integration.
“Every new customer should just work, with no ticket to us.”
Your own product team{default: true,provider: "s3",region: "ap-south-1",}Tenants without an override fall through to the default. Onboarding is a row in a table.
Three layers, evaluated top-down on every upload. Most tenants never touch the first two — which is exactly why onboarding them needs no engineer.
POST /v1/filesmetadata: { tenant: "acme", plan: "enterprise" }EU residency clause in contractpolicy.tenants[tenant]policy.plans[plan]policy.defaultwesteuropeA customer who starts on the default plan can end up in the EU, then in their own bucket, then asking for an audit — without your product ever learning where its files are.
tenant.createdacme signs up on the Team plan.
default → S3 · ap-south-1policy.updatedEnterprise contract adds an EU residency clause.
acme → Azure · westeuropefiles.moved12,408 objects relocated. Every file ID unchanged.
S3 → Azure · 0 broken linksstorage.connectedacme’s security team connects a bucket in their own account.
acme-own · scoped credentialspolicy.updatedPolicy now points at the customer-owned bucket.
acme → acme-ownfiles.moved14,102 objects relocated into their account.
Azure → acme-ownaudit.exportedAnnual audit: acme requests the full access log for their files.
per-tenant trail · 1 requestThe guarantees enterprise customers ask for, delivered by policy and ownership rather than by copies of your stack.
Routing decides where each tenant’s files go. You run one service and one database, not a stack per customer.
A connected bucket uses credentials the customer scopes and can revoke. Their files live in their account; you hold the record.
The tenant is metadata on the file, so access checks, exports and deletion can be scoped without a bucket per customer.
Uploads, retrievals, moves and deletes are recorded per file — filter by tenant and hand it over when procurement asks.
You tell it at upload: the tenant goes in the file’s metadata (and optionally a storage target). The routing policy reads it to pick a destination, and it stays on the record for access checks, exports and deletion later.
Yes. Connect their bucket as a storage connection with credentials they issue and scope, add a tenant override that points at it, and their files land there from the next upload. Existing files can be moved in with the same IDs.
Update the policy entry and move the objects. File IDs and every link built on them keep working, because the move only updates the location behind the ID.
No. Anyone without an override falls through to the plan rule or the default. Onboarding a standard customer is zero configuration.
Yes — most tenants share the default target. Every file record carries its tenant, access is only through signed URLs you issue after your own authorisation check, and there are no public object paths to guess.
Connect the buckets your customers need, write the policy, and ship the same upload call to every tenant.