Skip to main content
Apragya AI
Docs · Best Practices

Configuration over code: when to use TenantAppConfig

The platform's first design principle. What goes in tenant config, what doesn't, and how to keep your customisations from rotting.

Apragya AI's first design principle is configuration over code. Every dropdown, label, status, type, stage in the platform is tenant-configurable, NOT hardcoded. When you're tempted to write a code branch for a customer-specific behaviour, ask: could this be a TenantAppConfig setting instead? Almost always, the answer is yes.

What TenantAppConfig is

Per-tenant configuration storage on every Enterprise App. Keyed by (tenant_id, app_slug, config_key), stored as JSONB. Loaded once on first request, cached with a 60-second TTL. Reads cost nothing; writes invalidate the cache for that tenant + app combo.

What goes there

  • Dropdowns - stage names, status labels, category lists, priority levels
  • Custom field schemas - the JSON-Schema fragment that extends a record's shape per tenant
  • Taxonomies - the platform's category trees, customisable per tenant
  • Per-app routing rules, escalation chains, approval matrices
  • Per-app feature toggles inside the plan-feature-gate envelope
  • Tenant-specific labels and translations on UI strings

What does NOT go there

  • Business logic - if your customisation needs IF/ELSE branches, it's code, not config. Build it as a pipeline node or an agent prompt instead
  • Secrets - API keys, credentials, tokens belong in the encrypted credentials store, not tenant config
  • Large blobs - configs over 100KB get unwieldy in the JSONB. Move large content to object storage with a config row pointing to it
  • Cross-tenant data - if it would apply to all tenants the same way, it's platform config, not tenant config

The hardcoded-enum trap

The single most common platform anti-pattern: hardcoding a status / stage / type list in code, then realising six months later you need to add a value for a specific tenant. The fix is invasive - touch every reference, write a migration, update every dropdown, update every agent prompt that references the enum. Avoid by starting with TenantAppConfig from day one, even if today's value list is just 3 items.

When you write a feature, ask: "Could a business user customise this without a developer?" If the answer is no, you're probably hardcoding something that should be config. P8 in the platform principles - think like a Product Owner BEFORE you write code.

A real example

The CRM Pipeline ships with six stages: Discovery, Qualification, Proposal, Negotiation, Closed-Won, Closed-Lost. Hardcoded list, right? No. It's a TenantAppConfig key (crm.pipeline.stages) loaded fresh from JSONB per tenant. Acme Corp renames "Discovery" to "Cold" and adds a "Demo" stage between Qualification and Proposal. Zero code change. Acme's tenant sees the customised list everywhere - their dropdowns, their Kanban board, their agent prompts, their reports. Three other tenants on the same code path see the platform defaults.

Need help building this? Talk to a real engineer

← All docs
Ask Vippy anything