skip to content

Configuration & Secrets

Configuration belongs outside the artifact so the same build runs in every environment, delivered by a config server or platform. Secrets get stricter treatment through Vault or sealed secrets, with rotation and access control that plain config does not need.

part ofMicroservices architectureoverview, primer and where to startread it →
on this pageshow

questions

6

Why should application configuration (like database URLs, timeouts, or feature flags) be kept outside the compiled application artifact instead of hardcoded, especially when the same service runs in dev, staging, and production?

level: juniorimportance: must knowfreq 75%

answer

  1. build once deploy everywhere
  2. 12-factor config
  3. env vars vs hardcoded
  4. config != code
  5. secrets need extra protection

basics

~20 s

Because the same built package has to run in different places (laptop, test, live servers) that need different settings. If settings are baked into the code, you'd have to rebuild the whole app just to change a URL, and test settings could leak into production.

solid answer

~30 s

Externalizing config follows the 12-factor app principle: build one artifact once and deploy that same artifact everywhere, letting environment-specific values (DB connection strings, API keys, feature flags, timeouts) come from outside the code — environment variables, mounted files, or a config service. This decouples the deploy pipeline from configuration changes: you can flip a flag or rotate a credential without rebuilding. It reduces blast radius versus conditional branches inside code, and it keeps secrets out of source control.

go deeper

for a junior

Should know config shouldn't be hardcoded and can name env vars or a config file as the mechanism; doesn't need config-server internals.

for a middle

Should articulate the build-once-deploy-everywhere rationale and know Spring profiles or Kubernetes ConfigMaps as concrete mechanisms.

for a senior

Should discuss the secrets-vs-config distinction, fail-fast validation, and config drift as an operational risk across many services.

for a principal

Should reason about config as a cross-cutting platform capability — governance, audit trail, and the trade-off of centralizing vs distributing config ownership across dozens of teams.

## What "externalized configuration" means **Externalized configuration** means any value that changes between deploys or environments without changing the application's behavior in code — connection strings, credentials, thread-pool sizes, timeouts, feature flags, log levels — lives outside the compiled artifact and is injected at runtime. The **12-factor app** methodology's "Config" factor says: build one immutable artifact (a jar, a container image) and supply config at runtime via - environment variables, - mounted config files/ConfigMaps, - or a dedicated config service the app queries at startup. Concretely, a Spring Boot service reads defaults from `application.yml`, and Spring's property resolution order lets environment variables (like `DATABASE_URL`), JVM system properties, or a Config Server override those defaults per profile (`dev`, `staging`, `prod`) — so a Kubernetes ConfigMap or Secret mounted as env vars determines behavior without touching the built jar. ## Why it exists This exists because microservices multiply the number of places configuration lives. If values are hardcoded or baked in at build time, every environment needs its own build, which breaks the promise of "build once, promote the same artifact through the pipeline" and increases the risk that what you tested isn't actually what you ship. Externalizing config also separates **who can change config** (ops, SRE, feature owners) from **who can change code** (gated by code review and CI), enabling faster, lower-risk operational changes — like rotating a credential or tuning a timeout under load — without a full build-and-deploy cycle for every tweak. ## The trade-off, in both directions The trade-off runs both directions. Externalizing adds **indirection**. You now need a place to store, version, and secure config: - env vars in orchestrator specs, - a git-backed config repo, - a config server. And if that store is inconsistent across environments you get "works on my machine" bugs at the config layer instead of the code layer. **Over-externalizing** — turning every constant into a flag — creates config sprawl that's hard to audit, so mature setups add a config schema or validation step to keep it sane. And treating secrets as just another config value is itself a risky trade-off: **secrets need extra protection** (encryption, access auditing, rotation) that ordinary config doesn't, so lumping them into the same plaintext pipeline is a common anti-pattern. ## Failure modes in production In production, several failure modes recur. 1. **A missing or misspelled environment variable** can silently fall back to a default that's wrong for production (say, pointing at an in-memory test database) rather than causing a hard, obvious failure — this is why fail-fast validation at startup matters. 2. **Environment drift** is another: staging's ConfigMap slowly diverges from production's over months of ad hoc tweaks, until a staging-only bug appears in prod, or vice versa. 3. **Type mismatches** — a config value parsed as the string "true" in one environment's loader but expected as a boolean in another — can pass validation in one place and silently misbehave in another. 4. **Config dumped at startup** for debugging purposes can accidentally leak secrets into logs if secrets weren't segregated from ordinary config in the first place. ## Where it shows up A concrete real-world pattern: Kubernetes ConfigMaps and Secrets mounted as environment variables or volumes are now the standard runtime mechanism for this, often paired with a centralized store like **Spring Cloud Config** or **HashiCorp Consul** for per-service, per-environment key-value configuration that's centrally managed, versioned, and audited. This lets a platform team change a shared timeout value for many services in staging with a single commit, and roll it forward to production through the normal promotion pipeline, with zero code changes and zero rebuilds — exactly the operational agility that hardcoded configuration would make impossible.

  • What's the difference between a config value and a secret, and why might you treat them differently?
    A config value like a timeout or a feature flag isn't sensitive if exposed, whereas a secret like a database password grants access if leaked, so secrets need encryption at rest, access auditing, and rotation that ordinary config doesn't. Most shops route secrets through a dedicated store (Vault, a cloud secrets manager) rather than plain ConfigMaps or plaintext env-var files, and restrict who or what can read them. Mixing the two in one plaintext pipeline is a common security anti-pattern.
  • How would you validate that a required config value is present before a service starts serving traffic?
    Fail fast: on startup the service should assert that all required properties are present and well-typed and refuse to start, or fail its readiness probe, rather than starting with a null or default and misbehaving mysteriously on the first request. Spring Boot supports this via `@ConfigurationProperties` classes combined with JSR-303 validation annotations enforced at boot time.
  • If two services need slightly different timeout values in staging vs prod, where should that difference live?
    In profile- or environment-scoped config layers, such as Spring's `application-staging.yml` / `application-prod.yml` or separate namespace ConfigMaps, rather than in code branches like `if (env == "prod")`. That keeps the built artifact identical across environments and makes the difference visible and auditable in one place.

Like a stage play using the same script (the built app) in every city, just with different set dressing for each theater (env-specific config) — you don't rewrite the script per city, you just change what's on stage.

saying these in an interview costs you the question

  • Hardcodes environment checks like if (env == 'prod') in application code
  • Stores DB passwords in the same plaintext file as ordinary timeouts
  • Doesn't mention build-once-deploy-everywhere or an equivalent idea
  • Thinks rebuilding the app is the normal way to change a URL
  • No fail-fast validation for missing required config

context

open as a page

A team runs a Spring Cloud Config Server backed by a Git repository, serving configuration to 40 microservices. Walk through how a configuration change made in a git commit reaches a running service, and what has to happen for services to pick up the change without a restart.

level: middleimportance: must knowfreq 70%

basics

~20 s

The config values live in a separate git repo. A central 'config server' reads that repo and hands values to each service on request. Editing the repo alone doesn't reach running services — they either re-fetch on next restart or must be explicitly told to refresh live.

open as a page

You need a feature-toggle system used by 100+ microservices to gradually roll out a new checkout flow. What toggle types would you consider, where should toggle state live, and what should happen to a request if the toggle-evaluation service is unavailable mid-request?

level: seniorimportance: must knowfreq 60%

basics

~20 s

Use an on/off switch that can target a percentage of users, store its state somewhere fast and locally readable rather than deep inside one remote service, and make sure that if the switch-checking system goes down, requests fall back to a safe default instead of failing or exposing the risky new feature to everyone.

open as a page

What's the practical difference between storing a database password as a Kubernetes Secret (base64-encoded, mounted into a pod) versus fetching it at runtime from HashiCorp Vault using dynamic, short-lived credentials? What operational problem does each approach create?

level: middleimportance: should knowfreq 65%

basics

~20 s

A Kubernetes Secret is like a hidden config file with the password stored as-is (just encoded, not encrypted by default), and it doesn't expire. Vault instead hands out a temporary password that auto-expires, so a leak stops working soon. Vault is safer but more complex to run.

open as a page

A central config server outage blocks several services that are mid-deploy from starting, because they can't fetch their configuration at bootstrap. How would you architect configuration delivery so that a config-server outage doesn't cascade into a platform-wide outage?

level: seniorimportance: should knowfreq 55%

basics

~20 s

Don't make every service's ability to even start depend on one central system being up right now. Give each service a fallback: a locally cached copy of its last-known-good config it can start from if the central source is unreachable.

open as a page

In a GitOps pipeline, a team wants to commit their Kubernetes Secret manifests directly into the same git repository that drives deployment (for example via Bitnami's 'Sealed Secrets' controller), including in a repo with broad read access. How can a Secret be safely committed to git, and what does this pattern protect against versus what does it not protect against?

level: principalimportance: nice to knowfreq 30%

basics

~20 s

Normally you can't put a real password in git because anyone who can read the repo can read it. Sealed Secrets lets you encrypt the password first with a key only your cluster knows, so the encrypted version is safe to commit — only your cluster can turn it back into the real password.

open as a page