All posts
row-level securitydata productsbudget

Build a budget data product on a shared registry

gridmap team May 6, 2026 4 min read

A common conversation. A customer or partner asks for access to a slice of your data. The first instinct is custom infrastructure: a new database for that customer, a pipeline to keep it synced, maybe a small service in front. A few customers in, the maintenance cost exceeds the value of the data.

A cheaper pattern exists. One shared registry. One set of row-level security policies. One source of truth. Each customer sees only their slice. You maintain one thing.

Why per-customer infrastructure is expensive

The math gets ugly fast.

Customers Databases Pipelines Backups Audit trails
1 1 1 1 1
5 5 5 5 5
20 20 20 20 20

Every line in that table is recurring cost. Engineering hours to keep pipelines aligned. Storage. Backup windows. Compliance reviews. Five copies of "fix the migration" instead of one.

The customer does not need a database. They need filtered access to your data.

The shape of a shared registry

Four pieces:

  1. One registry table holding the full reference data.
  2. A consumer identity (user, API key, or token) that names the customer or partner.
  3. An RLS policy that filters rows by that identity.
  4. An API exposing the registry. The policy applies automatically; consumers never see rows they should not.

From the customer's point of view, the dataset is theirs. From your point of view, you maintain one database.

Where this fits naturally

  • Reference data products. A curated list of countries, currencies, taxonomies, industry codes. Tier the depth: free sees names, paid sees codes plus metadata, enterprise sees the long tail.
  • Partner portals. Each partner sees their own shipments or deals. One integration. One API.
  • Multi-tier SaaS. Same product, different visible rows or columns by plan. The plan is just a different policy.
  • Internal departments as customers. Marketing and finance both read the customer list with different visible attributes.

Approximate cost comparison

Item Per-customer infrastructure Shared registry + RLS
Storage Linear Constant
Pipelines Linear One
Onboarding Days to weeks Minutes
Schema change Once per customer Once
Bug fix to data Once per customer Once
Audit Spread One source

The shared pattern wins on every line, as long as the customers can live with filtered access.

Where this does not work

  • Schemas differ per customer. That is multi-tenancy, not RLS.
  • Hard data residency. A customer who must have their data physically in a specific region needs regional databases.
  • Per-customer writes. RLS controls reads. Writes need separate policy and often imply per-customer state, which weakens the shared model.
  • Provable physical separation required. Some regulated industries require isolation, not policies.

If none of those apply, the shared pattern is almost always the right answer.

A minimum viable setup checklist

  • A registry table with a customer_id (or tenant_id) column on every row that needs filtering.
  • An API key or token model that carries the customer identity.
  • An RLS policy on the registry that compares the row's customer_id to the caller's identity.
  • An API in front of the registry. The policy applies automatically.
  • A way for the customer to see what subset they have (a metadata endpoint or a documented data dictionary).
  • Optionally, a read audit log. Useful, not always required.

This is what gridmap's RLS registries are built for. Permissions can live inside gridmap, or sync from a warehouse table where the team or customer model already lives. The Lookup API in front of the registry applies the policy on every read. Adding a new customer is creating an API key, not provisioning infrastructure.

FAQ

Can a customer tell they are seeing a filtered view? Only if you tell them. RLS is invisible to the caller. A row count of zero is the only common tell.

How do we price this? Tier the policy, not the database. Which rows or columns the customer sees, not how much storage they consume.

What if a customer needs to write data? Add a small writable extension table keyed by customer. The shared registry stays clean. Customer-specific state lives in a thin per-customer layer.

The point of this pattern is to make per-customer cost approach zero. Then "should we share this data with this customer" becomes a product decision, not an engineering one.