Tutorial

How to Choose a Config Management Strategy

Choose a config management strategy by weighing file, env, and service, so the config is testable, secret-safe, and hot-reloadable as needed.

On this page

  1. Introduction
  2. List the requirements
  3. Weigh file vs env
  4. Consider a service
  5. Decide on secrets
  6. Plan for hot reload
  7. Document the choice
  8. Common pitfalls
  9. Conclusion

Introduction

The hardest part of pick the right approach is not writing the code — it is deciding what the code is allowed to reject. A config strategy setup that accepts everything is easy to ship and expensive to operate, because every malformed input becomes a production surprise. The discipline is to enumerate the shapes the system actually receives, encode them in config strategy, and let the library reject the rest loudly. This keeps the happy path fast and the failure path visible.

config strategy earns its place when pick the right approach is the bottleneck the user feels. Before that, it is overhead that slows the common case to protect a rare one. Measure the rejection rate and the tail latency, then decide whether the guard is worth its cost. A guard that never fires is a guard you can remove; a guard that fires constantly is a signal that the producer contract is wrong, not that the guard is too strict.

The sections below walk through the concrete decisions: where to put the config strategy check, how to keep it fast under load, what to do when the contract changes, and how to test the failure paths so they degrade on purpose instead of by accident.

List the requirements

List the requirements is the first decision because it determines what the rest of the config strategy pipeline can assume. A wrong choice here turns into pick the right approach under load, and the invariant you thought config strategy guaranteed no longer holds. Measure the impact before committing, because the cost of a bad choice is paid in incidents, not in a code review.

The test for List the requirements is the one most teams skip: drive config strategy to the failing condition and assert the system degrades gracefully. Write it with a fake clock for time-based logic, a stub for the failure path, and an assertion on the user-visible outcome. A test that passes by timing out is a hope, not a test.

// file for shape, env for secrets, service for dynamic
const cfg = { ...file, ...env, ...await configService.get() };

The javascript above is the shape to ship for pick the right approach. It is small enough to audit and specific enough that the failure behavior is obvious. Adapt the constants to your traffic and latency budget, and resist the urge to handle cases the system has not seen yet.

Weigh file vs env

The mechanism behind Weigh file vs env is straightforward in config strategy, but the consequences ripple. A wrong choice here turns into pick the right approach under load, and the invariant you thought config strategy guaranteed no longer holds. Measure the impact before committing, because the cost of a bad choice is paid in incidents, not in a code review.

The test for Weigh file vs env is the one most teams skip: drive config strategy to the failing condition and assert the system degrades gracefully. Write it with a fake clock for time-based logic, a stub for the failure path, and an assertion on the user-visible outcome. A test that passes by timing out is a hope, not a test.

Consider a service

Consider a service is where most config strategy implementations leak performance. A wrong choice here turns into pick the right approach under load, and the invariant you thought config strategy guaranteed no longer holds. Measure the impact before committing, because the cost of a bad choice is paid in incidents, not in a code review.

The test for Consider a service is the one most teams skip: drive config strategy to the failing condition and assert the system degrades gracefully. Write it with a fake clock for time-based logic, a stub for the failure path, and an assertion on the user-visible outcome. A test that passes by timing out is a hope, not a test.

test('strategy meets requirements', () => {
  expect(cfg).toMatchObject(required);
});

Pin the behavior with this test. A config strategy setup that passes this test degrades on purpose instead of by accident, which is the difference between a managed failure and an incident.

Decide on secrets

The hard part of Decide on secrets is not the happy path — it is what happens when config strategy fails halfway. A wrong choice here turns into pick the right approach under load, and the invariant you thought config strategy guaranteed no longer holds. Measure the impact before committing, because the cost of a bad choice is paid in incidents, not in a code review.

The test for Decide on secrets is the one most teams skip: drive config strategy to the failing condition and assert the system degrades gracefully. Write it with a fake clock for time-based logic, a stub for the failure path, and an assertion on the user-visible outcome. A test that passes by timing out is a hope, not a test.

Plan for hot reload

Plan for hot reload should be observable without a debugger. A wrong choice here turns into pick the right approach under load, and the invariant you thought config strategy guaranteed no longer holds. Measure the impact before committing, because the cost of a bad choice is paid in incidents, not in a code review.

The test for Plan for hot reload is the one most teams skip: drive config strategy to the failing condition and assert the system degrades gracefully. Write it with a fake clock for time-based logic, a stub for the failure path, and an assertion on the user-visible outcome. A test that passes by timing out is a hope, not a test.

Document the choice

Document the choice is a trade, not a winner. A wrong choice here turns into pick the right approach under load, and the invariant you thought config strategy guaranteed no longer holds. Measure the impact before committing, because the cost of a bad choice is paid in incidents, not in a code review.

The test for Document the choice is the one most teams skip: drive config strategy to the failing condition and assert the system degrades gracefully. Write it with a fake clock for time-based logic, a stub for the failure path, and an assertion on the user-visible outcome. A test that passes by timing out is a hope, not a test.

Common pitfalls

The common pitfalls in pick the right approach all reduce to one mistake: treating config strategy as a formality instead of a contract. The contract is the thing the rest of the system relies on, and a weak contract propagates weakness everywhere.

  • Skipping the config strategy boundary so pick the right approach enters unvalidated.
  • Assuming config strategy is fast without measuring the tail latency under load.
  • Letting pick the right approach fail silently instead of failing loudly with a metric.
  • Testing only the happy path so the config strategy failure surfaces in production.
  • Sharing mutable state across requests so one bad input poisons the next.

Conclusion

Do not conflate the conclusion with the implementation. They look similar from the outside but the failure modes differ: config strategy fails fast and the caller knows, while an unchecked path fails slow and the caller guesses. Choose the one whose failure mode your system can absorb, and document the choice at the call site.

Self-check: write a test that drives config strategy to the failing condition and assert the system degrades gracefully. Then pick the right approach is a property you maintain, not a feature you hope for.

Sources: 12-factor, Config service

FAQ

When a config service?
When you need hot reload, dynamic secrets, or tenant overrides. Otherwise file + env is enough.
Secrets?
Never in file or env in prod. Use a secret store.

Related Examples