Skip to content
Kumar Chandrachooda
Data Warehousing

Feature Flags Inside the Database

KC Star V7 ships a six-table feature-flag system so you can turn capabilities on and retune settings without a deploy. Here is the normalized flag model, the twenty-one seeded flags, and the honest gap between what the changelog documents and what the code ships.

By Kumar Chandrachooda 18 Dec 2025 5 min read
A panel of toggle switches living inside a database cylinder

The batch pipeline has knobs: batch size, the age gate, whether partitioning is on, how often monitoring runs. Baking those into the SQL means a code change and a redeploy every time you want to retune. V7's answer is to put the knobs inside the database — a feature-flag system that lets you flip capabilities and adjust settings at runtime, with no deploy. This post is that system: its six-table model, its twenty-one seeded flags, and an honest accounting of where the changelog and the code disagree about it.

Not a flat table

If you have built feature flags before, you probably reached for one table: a name, a boolean, maybe a description. The V7 CHANGELOG even describes it that way. The actual code ships something much more elaborate — a six-table normalized model:

  • FeatureCategories — six categories (Performance, Data Management, Security, Monitoring, Analytics, System) to group flags.
  • FeatureFlags — the flags themselves: FeatureName UNIQUE, a CategoryId, IsEnabled, DefaultValue, IsSystemFeature, RequiresRestart.
  • FeatureSettings — typed settings per flag: SettingName, SettingValue, DataType, DefaultValue, MinValue, MaxValue, ValidationRule, unique per (feature, setting).
  • FeatureDependencies — relationships between flags: REQUIRES, CONFLICTS, OPTIONAL.
  • FeatureAuditLog — who changed what flag when, with old and new values and a reason.
  • FeatureStatus — runtime state: ACTIVE/INACTIVE/ERROR, an error count, performance metrics as JSONB.

That is a lot more than a boolean column, and the extra structure buys real things. Settings are typed and bounded — a batch size has a MinValue and MaxValue, so you cannot set it to nonsense. Flags have dependencies — enabling one can require another and conflict with a third. Every change is audited. And flags can be marked RequiresRestart or IsSystemFeature, so the system knows which toggles are safe to flip live and which are load-bearing.

Twenty-one flags

V7 seeds twenty-one flags across the categories, and reading the list is a decent map of what V7 can do:

BATCH_PROCESSING_ENABLED (TRUE), INDEX_OPTIMIZATION_ENABLED,
CACHE_ENABLED (FALSE, RequiresRestart), REAL_TIME_UPDATES_ENABLED,
DATA_QUALITY_MONITORING_ENABLED, AUTO_CLEANUP_ENABLED, COMPRESSION_ENABLED,
PARTITIONING_ENABLED (FALSE), RBAC_ENABLED, AUDIT_LOGGING_ENABLED,
ENCRYPTION_ENABLED, PERFORMANCE_MONITORING_ENABLED, ALERTING_ENABLED,
HEALTH_CHECKS_ENABLED, AUTOMATED_MONITORING_ENABLED,
FACT_CHANGES_ANALYSIS_ENABLED, ADVANCED_AGGREGATIONS_ENABLED,
TIME_TRAVEL_QUERIES_ENABLED, FEATURE_FLAG_SYSTEM_ENABLED (system, cannot disable),
SCHEDULED_JOBS_ENABLED, AUTO_SCALING_ENABLED

Two are worth calling out. PARTITIONING_ENABLED defaults to FALSE — the partitioning subsystems are opt-in, off until you decide you need them. And FEATURE_FLAG_SYSTEM_ENABLED is a IsSystemFeature flag that cannot be disabled — you cannot turn off the thing that turns things off, which is the kind of bootstrap protection you appreciate the first time someone tries.

Flipping flags at runtime

The functions read and write flags without touching code. IsFeatureEnabled checks a flag; SetFeatureEnabled flips one, writing an audit-log entry as it goes; GetFeatureSetting and SetFeatureSetting read and write the typed settings. So retuning the batch pipeline is a couple of function calls, live:

-- turn partitioning on, with a reason for the audit log
SELECT SetFeatureEnabled('PARTITIONING_ENABLED', TRUE, 'ADMIN',
       'Enabling partitioning for better performance');

-- retune a setting, bounded by its Min/Max
SELECT SetFeatureSetting('PARTITIONING_ENABLED', 'BACKUP_DAYS_OLD', '45');

No deploy, no migration, no restart (unless the flag says RequiresRestart). The change takes effect on the next IsFeatureEnabled check, and the FeatureAuditLog records who did it and why. That is the whole value proposition: operational behaviour becomes data you can edit, not code you have to ship. For a warehouse that has to be retuned under changing load, that is exactly the right place to put the knobs — and the self-adjusting scheduler in the next post writes its own decisions straight back into FeatureSettings, which only works because the settings live in a table.

The drift, named honestly

I keep a rule through this whole series: the code is ground truth, the changelog is a claim. Feature flags are a smaller instance of the same drift, and I will name all of it.

The CHANGELOG documents a flat table. It describes FeatureFlags as roughly (FeatureName PRIMARY KEY, IsEnabled, Category, Description) — the one-table design. The code ships the six-table normalized model above. If you learned V7's flags from the changelog, you would be surprised by five tables you had never heard of.

The function names disagree too. The README refers to GetFeatureEnabled(). The implemented function is IsFeatureEnabled(). There is no GetFeatureEnabled in the code. Grep for the documented name and you get nothing; grep for the real one and you find it everywhere.

The V8 changelog even has a copy-paste typo in this area, listing SettingName twice in the FeatureSettings definition — a small tell that the documentation was assembled by hand and not checked against the DDL.

None of these break the system; the code is internally consistent and the flags work. But they are exactly the kind of small, quiet documentation drift that compounds into the V6 situation if left unchecked. I show them for the same reason I show the variable-shadowing bug: the honest record of a real system includes the places where its documentation and its code stopped agreeing.

Why the elaborate model was worth it

You might reasonably ask whether a six-table feature-flag system is over-engineered for a warehouse. For most projects, yes — a boolean column would do. I built the elaborate version because V7's flags are not just on/off switches; several of them, especially the monitoring and partitioning flags, carry tunable numeric settings that the system itself reads and writes at runtime. Typed, bounded, audited settings are worth the structure once your flags have parameters that change under load. A flag that is only ever a boolean does not need five supporting tables; a flag whose BACKUP_DAYS_OLD setting the scheduler rewrites on the fly does.

That self-writing scheduler is the most interesting thing V7 does with these flags, and it is next: the scheduler that reads its own health, where the warehouse scores its own condition and retunes its own batch cadence in response.