B2B Use case · Multi-tenant platforms

One codebase.
Every customer’s storage rules.

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.

Route by tenant, plan or region Customer-owned buckets Move tenants without changing an ID
ONE DEPLOYMENTROUTING POLICYWHERE EACH TENANT LANDSAPPYour platformone codebase · uplint.filestenant:initechTeamacmeEnterpriseglobexEnterpriseumbrellaBusinessPOST /v1/files · same call for allustorage.policy4 rulesacmeEU residencyAZ · westeurope→globexown bucketS3 · globex-files→umbrellaprovider: gcsGC · asia-south1→* defaulteveryone elseS3 · ap-south-1→S3AWS S3ap-south-1your accountAZAzure Blobwesteuropeyour accountS3AWS S3globex-filescustomer-ownedGCGoogle Cloudasia-south1your accountINIfile_7Hq21cACMfile_8Kx92mGLOfile_Zp40dmUMBfile_c9Lm2e
02 What customers ask for

Four asks that once
meant four stacks.

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
Data residency
{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
Customer-owned storage
{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
Provider preference
{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
A sensible default
{default: true,provider: "s3",region: "ap-south-1",}

Tenants without an override fall through to the default. Onboarding is a row in a table.

03 How routing decides

Override. Plan. Default.
Top-down, on every upload.

Three layers, evaluated top-down on every upload. Most tenants never touch the first two — which is exactly why onboarding them needs no engineer.

Upload from
POST /v1/filesmetadata: { tenant: "acme", plan: "enterprise" }EU residency clause in contract
Policy evaluates
  1. 1
    Tenant overridepolicy.tenants[tenant]
    match
  2. 2
    Plan rulepolicy.plans[plan]
    —
  3. 3
    Defaultpolicy.default
    —
Lands in
Azure Blobwesteurope
your account
Same upload call. Same file ID format. Only the destination differs.
04 A tenant over time

Requirements change.
File IDs don’t.

A 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.

  • Moves are one call; links keep working
  • Policy changes are configuration, not a release
  • Every event is on the record, per tenant
tenant: acmeevents · storage
Day 0
tenant.created

acme signs up on the Team plan.

default → S3 · ap-south-1
Month 3
policy.updated

Enterprise contract adds an EU residency clause.

acme → Azure · westeurope
Month 3
files.moved

12,408 objects relocated. Every file ID unchanged.

S3 → Azure · 0 broken links
Year 1
storage.connected

acme’s security team connects a bucket in their own account.

acme-own · scoped credentials
Year 1
policy.updated

Policy now points at the customer-owned bucket.

acme → acme-own
Year 1
files.moved

14,102 objects relocated into their account.

Azure → acme-own
Year 2
audit.exported

Annual audit: acme requests the full access log for their files.

per-tenant trail · 1 request
05 Isolation & ownership

Isolation without
a deployment per customer.

The guarantees enterprise customers ask for, delivered by policy and ownership rather than by copies of your stack.

Per-tenant destinations, one deployment

Routing decides where each tenant’s files go. You run one service and one database, not a stack per customer.

Customer-owned buckets, customer-issued credentials

A connected bucket uses credentials the customer scopes and can revoke. Their files live in their account; you hold the record.

Tenant on every record

The tenant is metadata on the file, so access checks, exports and deletion can be scoped without a bucket per customer.

An audit trail a customer can read

Uploads, retrievals, moves and deletes are recorded per file — filter by tenant and hand it over when procurement asks.

06 Questions

Straight answers.

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.

THE NEXT ENTERPRISE DEAL HAS A STORAGE CLAUSE.

Say yes to the clause.
Keep one codebase.

Connect the buckets your customers need, write the policy, and ship the same upload call to every tenant.