Skip to content
The configuration OS for multi-tenant SaaS

Every tenant.Every key.In custody.

TenaVault versions, approves, and audits every customer-specific configuration your product runs on — and delivers it to your app in microseconds. No more mystery values in production.

Resolution · limits.api_rate_per_min
meridian-capital
Globaldefaults
500
Environmentproduction
Templategrowth-tier
Effective900
Tenantmeridian-capital
Effective2000
Sealed · v41 · a3f9c21
Delivered in 3µs · local snapshot
Scroll — the 2:47 AM story
14:42:07 limits.api_rate_per_min · acme-corp · 600 → 900 · sealed ✓· · ·14:38:12 flags.new_dashboard · globex · false → true · sealed ✓· · ·14:31:55 billing.proration_mode · globex · daily → none · ⚠ unmanaged write· · ·14:26:40 routing.priority_queue · initech · standard → dedicated · sealed ✓· · ·14:19:03 limits.storage_gb · northwind · 250 → 500 · sealed ✓· · ·14:11:47 auth.session_ttl_min · contoso · 30 → 15 · ⚠ unmanaged write· · ·14:05:22 billing.trial_days · umbra · 14 → 30 · sealed ✓· · ·
14:42:07 limits.api_rate_per_min · acme-corp · 600 → 900 · sealed ✓· · ·14:38:12 flags.new_dashboard · globex · false → true · sealed ✓· · ·14:31:55 billing.proration_mode · globex · daily → none · ⚠ unmanaged write· · ·14:26:40 routing.priority_queue · initech · standard → dedicated · sealed ✓· · ·14:19:03 limits.storage_gb · northwind · 250 → 500 · sealed ✓· · ·14:11:47 auth.session_ttl_min · contoso · 30 → 15 · ⚠ unmanaged write· · ·14:05:22 billing.trial_days · umbra · 14 → 30 · sealed ✓· · ·
.env.productionunmanaged
RATE_LIMIT=1200 # temp fix??
support ticket #4131unmanaged
customer says limit was raised in march
k8s configmapunmanaged
RATE_LIMIT: "600" last-applied: ???
postgres · tenant_settingsunmanaged
rate_limit = 900 updated_by = ???
cron · nightly.shunmanaged
UPDATE settings SET tier='growth'
redis · overridesunmanaged
acme:rate 900 TTL: none
flags · dashboardunmanaged
new_dashboard: ON 47 tenant overrides
#eng-oncall · slackunmanaged
did anyone change acme’s limits??
limits_v2.xlsxunmanaged
acme 600 → 900? (see tab 3)
email · fwd: fwd:unmanaged
just set it directly in prod for now
Config lives everywhere. So the truth lives nowhere.
Env files, admin panels, spreadsheets, a Redis override someone set at 2 AM. When something breaks, nobody knows what changed, who changed it, or what the value was before.
no review · no history · no rollback

One ledger. Every change. Sealed.

postgres
tenants.yaml
feature flags
slack thread
.env files
the wiki
TimeActorKeyChangeStatus
14:42:07r.okaforlimits.api_rate_per_min600 900sealed ✓
14:38:12j.tanflags.new_dashboardfalse truesealed ✓
14:31:55deploy-botbilling.proration_modedaily nonesealed ✓
14:26:40r.okaforrouting.priority_queuestandard dedicatedsealed ✓
14:19:03m.silvalimits.storage_gb250 500sealed ✓
14:05:22j.tanbilling.trial_days14 30sealed ✓
01 / Custody

Know what's live, and why.

Global → environment → template → tenant. One resolution order, enforced by the platform — not by memory.

vault.tenavault.com/registry
KeyScopesEffective
limits.api_rate_per_minG · T · TEN2000
GLOBAL 500ENV —TEMPLATE 900TENANT 2000Effective
flags.new_dashboardG · TENtrue
billing.proration_modeG · Tdaily
limits.storage_gbG · E · TEN500
vault.tenavault.com/changes/CR-142
CR-142 · raise api rate limit — meridian-capitalOpen
- limits.api_rate_per_min = 900
+ limits.api_rate_per_min = 2000
✓ schema valid✓ policy · within limits.max✓ canary · 0 errors
ROJT2 / 2 approved
Seal & deploy
02 / Ceremony

Changes are proposed,

Diff, checks, discussion, approval. The seal is the deploy.

03 / Memory

The ledger never

Every write records who, what, when, and the value before. Rewind the entire org to any second.

vault.tenavault.com/ledger
Rewind to
2026-07-06 14:42:07
TimeKeyValue
14:42limits.api_rate_per_min900
14:26routing.priority_queuededicated
14:05billing.trial_days30
who · what · when · value before — for every write
Delivery plane
VaultSnapshot
a3f9c21 · signed
CDN edgeYour app
local SDK
push · SSE · ~1setag · 304 when unchangedoffline · last snapshot wins
04 / Delivery

Reads in microseconds,

Signed snapshots on a CDN. Local-first SDK. Offline fallback. SSE push in ~1s.

import { TenaVault } from '@tenavault/sdk';

const vault = await TenaVault.init({
  org: 'acme',
  tenant: 'meridian-capital',
  sdkKey: process.env.TV_KEY,
});

const limit = vault.get('limits.api_rate_per_min');
// → 2000 · 3µs · local snapshot

vault.listen(onChange);
// SSE push · ~1s propagation
3µs
p50 read
Values resolve from a local snapshot in process memory. No network on the read path.
~1s
propagation
A sealed change reaches every connected SDK over SSE in about one second.
100%
offline fallback
If the delivery plane is unreachable, your app keeps running on the last signed snapshot.
Read the docs →
The point
Every value accountable. Every change in the ledger. Every tenant exactly what you meant — and never a config nobody can explain.
That is configuration in custody.
SSO · SCIM · RBAC
Enterprise identity from day one.
Governed by default
Every change needs a seal before it deploys.
Append-only ledger
Every write, forever — who, what, when, before.
Local-first SDK
Reads never leave your process — offline fallback built in.

Questions, answered.

What is TenaVault?

TenaVault is a configuration governance platform for multi-tenant SaaS. Every customer-specific config value is versioned, scoped (global → environment → template → tenant, most specific wins), proposed and approved through a change request before it takes effect, and recorded in an append-only ledger — so you always know who changed what, when, and why.

How is TenaVault different from a feature-flag platform like LaunchDarkly or Split?

Feature flags are built for toggling behavior on or off, usually per environment or user segment. TenaVault is built for configuration: typed values — numbers, strings, booleans, or whole nested JSON documents — that vary per customer (tenant), changed through a real propose-approve-merge workflow rather than a simple toggle, with a configurable approval chain instead of a single switch.

Does TenaVault replace environment variables?

No. Environment variables are fine for config that's the same across every customer. TenaVault is for config that varies per tenant — the kind that today ends up scattered across spreadsheets, Slack threads, and one-off database rows nobody remembers changing.

What does "governed configuration" actually mean?

Every write is proposed, then approved — optionally through a configurable multi-step approval matrix requiring specific people or roles to sign off in order — then applied. Every action along the way, including who approved what and when, lands in an append-only ledger that is never edited or deleted. A rollback is a new ledger entry restoring a prior value, not a rewrite of history.

How fast is a config read at runtime?

The SDK boots from a single snapshot fetch, then serves every subsequent read from an in-memory snapshot — reads never touch the network. Updates to connected SDKs propagate over a live stream in about a second, and if TenaVault's delivery plane is unreachable, the SDK keeps serving the last known-good snapshot instead of breaking your app.

Can I roll back a bad configuration change?

Yes. Rollback restores a prior version by writing a new ledger event — the change history is append-only and is never edited or deleted, so you can always see exactly what happened, in order.

Is there an audit trail for compliance?

Yes. Every proposal, approval, merge, and rollback is recorded in an append-only ledger with the actor, timestamp, and exact before/after value. Nested config documents additionally support a git-blame-style view showing who last touched any specific field and when, for line-level audit detail.

Which languages or frameworks does the TenaVault SDK support?

A Node/TypeScript SDK is available today. TenaVault's resolution logic is deliberately kept as a portable, dependency-free module so additional language SDKs can be built against the same scope-resolution semantics.

Can TenaVault integrate with config we already have in Postgres, GitHub, or Redis?

Yes, through connectors that watch or mirror an existing source — a Postgres table, a GitHub repo of config files, a Redis keyspace — so you can bring configuration under governance gradually instead of a big-bang migration on day one.

Put your configuration in custody.

30 minutes with our founding team. Your messiest tenant config. We'll show you exactly how it comes under governance.

Book a demo
no forms longer than 60 seconds · no spam · real engineers on the call
Prefer email? hello@tenavault.com
14:42:07 limits.api_rate_per_min · acme-corp · 600 → 900 · sealed ✓· · ·14:38:12 flags.new_dashboard · globex · false → true · sealed ✓· · ·14:31:55 billing.proration_mode · globex · daily → none · ⚠ unmanaged write· · ·14:26:40 routing.priority_queue · initech · standard → dedicated · sealed ✓· · ·14:19:03 limits.storage_gb · northwind · 250 → 500 · sealed ✓· · ·14:11:47 auth.session_ttl_min · contoso · 30 → 15 · ⚠ unmanaged write· · ·14:05:22 billing.trial_days · umbra · 14 → 30 · sealed ✓· · ·
14:42:07 limits.api_rate_per_min · acme-corp · 600 → 900 · sealed ✓· · ·14:38:12 flags.new_dashboard · globex · false → true · sealed ✓· · ·14:31:55 billing.proration_mode · globex · daily → none · ⚠ unmanaged write· · ·14:26:40 routing.priority_queue · initech · standard → dedicated · sealed ✓· · ·14:19:03 limits.storage_gb · northwind · 250 → 500 · sealed ✓· · ·14:11:47 auth.session_ttl_min · contoso · 30 → 15 · ⚠ unmanaged write· · ·14:05:22 billing.trial_days · umbra · 14 → 30 · sealed ✓· · ·