Q218: Type Safe Feature Flags, Config and Experimentation
What Interviewers Want To Evaluate
Interviewers want to know whether you can manage runtime configuration safely.
They check feature flag typing, experiment variants, remote config validation, rollout safety, kill switches, stale flag cleanup, and how flags interact with performance and TypeScript boundaries.
Short Interview Answer
I type feature flags and config as explicit contracts, then validate remote values at runtime before using them. Flags should have owners, defaults, rollout strategy, expiry dates, and cleanup plans. TypeScript can prevent invalid flag names or experiment variants in code, but runtime config still needs validation because remote values can be missing, stale, or malformed.
Detailed Interview Answer
Feature flags are powerful because they decouple deploy from release.
They also add complexity.
Flags can affect:
rendered UI
bundle loading
experiments
performance budgets
third-party scripts
checkout or signup flows
access control visibility
operational kill switches
TypeScript helps keep names and variants controlled.
Runtime validation keeps remote config honest.
Flag Registry
Create a registry of known flags.
type FeatureFlag =
| "new_question_reader"
| "typescript_practice_v2"
| "defer_vendor_scripts"
| "batch_pdf_download";
Then type access.
type FlagState = Record<FeatureFlag, boolean>;
function isEnabled(flags: FlagState, flag: FeatureFlag) {
return flags[flag];
}
This prevents misspelled flag names.
Config With Variants
Experiments often need variants, not booleans.
type ReaderLayoutVariant = "control" | "compact" | "guided";
type ExperimentConfig = {
readerLayout: ReaderLayoutVariant;
practiceConsole: "side-by-side" | "stacked";
};
Use literal unions for known variants.
Do not let arbitrary strings flow through the app.
Runtime Validation
Remote config is runtime data.
function parseReaderLayout(value: unknown): ReaderLayoutVariant {
if (value === "control" || value === "compact" || value === "guided") {
return value;
}
return "control";
}
Default safely when config is missing or invalid.
Owner And Expiry Metadata
Flags need lifecycle metadata.
type FlagMetadata = {
owner: string;
createdAt: string;
expiresAt: string;
description: string;
cleanupIssue?: string;
};
A flag without cleanup becomes permanent complexity.
The team should know who owns it and when it should be removed.
Performance Flags
Flags can protect performance rollouts.
type PerformanceFlag =
| "defer_vendor_scripts"
| "lazy_load_editor"
| "disable_heavy_animation";
These flags can act as kill switches.
If INP regresses after a release, a flag can disable expensive work while a deeper fix is prepared.
Experiment Event Typing
Experiments need exposure tracking.
type ExperimentExposure = {
experiment: keyof ExperimentConfig;
variant: string;
route: string;
release: string;
};
For stronger typing, map experiment names to variants.
type ExperimentExposureMap = {
readerLayout: ReaderLayoutVariant;
practiceConsole: "side-by-side" | "stacked";
};
function trackExposure<TExperiment extends keyof ExperimentExposureMap>(
experiment: TExperiment,
variant: ExperimentExposureMap[TExperiment],
) {
console.log(experiment, variant);
}
Invalid experiment/variant pairs fail at compile time.
Server And Client Config
Not all config belongs on the client.
Server-only:
secret keys
private rollout rules
pricing logic
security policies
internal endpoints
Client-safe:
visual variant
non-sensitive feature visibility
public experiment assignment
performance behavior toggles
Keep secrets out of Client Components.
Common Mistakes
Common mistakes include:
using raw strings for flag names
trusting remote config without defaults
leaving stale flags forever
using flags as authorization
shipping secret config to the client
forgetting exposure events
running experiments without success metrics
Flags should reduce release risk, not create hidden product forks.
Senior Trade-Offs
Flags add operational control.
They also add branches.
I would require:
typed registry
runtime parsing
safe defaults
owner and expiry
exposure tracking
kill switch strategy
cleanup after rollout
For short-lived local UI toggles, this can be lighter.
For production experiments, governance matters.
Interview Framing
In an interview, say:
I type flag names and experiment variants so code cannot use invalid values. Because config is remote runtime data, I parse it, default safely, track exposures, and require owners plus cleanup dates.
Revision Notes
- Flags decouple deploy from release.
- Type flag names and experiment variants.
- Remote config still needs runtime validation.
- Defaults should be safe.
- Flags need owner, expiry, and cleanup.
- Performance flags can act as kill switches.
Follow-Up Questions
- Why are raw string flag names risky?
- How would you type experiment variants?
- Why is runtime config validation necessary?
- What metadata should a flag have?
- How can flags help with performance incidents?
How I Would Answer This In A Real Interview
I would say feature flags are runtime control points, so they need both type safety and operational discipline. I would type known flags and variants, validate remote values, provide safe defaults, track experiment exposure, and require ownership plus cleanup. I would also separate server-only config from client-safe config to avoid leaking secrets or critical logic.