How is the Consul KV store used as a configuration backend for Spring Boot, and how do property keys map into the environment?
answer
- starter-consul-config + config.import=consul:
- prefix config/ → application/ + {app-name}/
- format KEY_VALUE vs YAML blob (data key)
- profiles: config/{name},prod/
- watch + @RefreshScope = live refresh
basics
~10 sAdd spring-cloud-starter-consul-config and import consul: config. Spring reads keys under a prefix like config/<app-name>/ from Consul's KV store and exposes them as normal Spring properties, with app-specific keys overriding shared ones.
solid answer
~40 sConsul's **KV store** is a hierarchical key/value database. With `spring-cloud-starter-consul-config` and `spring.config.import=consul:` (or the legacy bootstrap path), Spring Cloud reads keys under a configurable prefix — default `config/` — organized as `config/application/` (shared defaults) and `config/{spring.application.name}/` (app-specific overrides), plus profile-specific folders like `config/order-service,prod/`. These become a `PropertySource` in the Environment, so values are injectable via `@Value`, `@ConfigurationProperties`, etc. Values can be stored as individual keys or as a single YAML/properties blob under one key (`format: yaml`, key `data`), controlled by `spring.cloud.consul.config.format`. Precedence follows Spring's usual ordering: profile-specific and app-specific override shared. With Spring Cloud's `@RefreshScope` plus watch enabled, changes in KV can trigger a `/actuator/refresh` and live re-binding without restart.
code
yaml · 23 linesspring:
application:
name: order-service
config:
import: "optional:consul:" # optional: don't fail if agent absent
cloud:
consul:
host: localhost
port: 8500
config:
enabled: true
prefix: config
default-context: application
format: YAML # store a YAML blob under the 'data' key
data-key: data
watch:
enabled: true
delay: 1000
---
# In Consul KV:
# config/application/data -> shared YAML
# config/order-service/data -> app-specific YAML (overrides shared)
# config/order-service,prod/data -> prod overridesgo deeper
Know Consul has a KV store Spring can read as config, keyed by app name under a prefix.
Explain prefix/context/profile layout, KEY_VALUE vs YAML format, and config.import wiring.
Discuss precedence ordering, watch-based live refresh via @RefreshScope, and fail-fast behavior.
Weigh Consul Config vs Config Server vs Vault, secret handling, refresh blast radius, and multi-env key governance.
**The KV store.** Beyond service discovery, Consul ships a distributed **key/value store** — a flat namespace where keys look like filesystem paths (`config/order-service/db/url`). It's replicated across Consul servers via Raft, so reads are consistent and durable. Spring Cloud Consul Config turns this into an externalized-configuration source, an alternative to Spring Cloud Config Server. **Wiring it up.** Add `spring-cloud-starter-consul-config`. Two mechanisms exist: 1. **Modern (`spring.config.import`)**: put `spring.config.import=consul:` (optionally `consul:host:port`) in `application.yml`. No bootstrap context needed. 2. **Legacy (bootstrap)**: enable the bootstrap context (`spring-cloud-starter-bootstrap` or `spring.cloud.bootstrap.enabled=true`); config is loaded before the main context. **Key layout / prefix.** Controlled by `spring.cloud.consul.config.*`: - `prefix` — root, default `config`. - `default-context` — shared folder name, default `application` → `config/application/...` applies to all apps. - App context = `config/{spring.application.name}/...`. - Profiles: with `profile-separator` (default `,`), a `prod` profile reads `config/{name},prod/` and `config/application,prod/`. **Value formats** (`spring.cloud.consul.config.format`): - `KEY_VALUE` (default) — each leaf key is one property. `config/order-service/db/url` → property `db.url`. - `PROPERTIES` / `YAML` — one KV key (named by `data-key`, default `data`) holds a whole properties/YAML document that Spring parses. Cleaner for large configs and easier to edit as a blob. - `FILES` — multiple named files. **Property resolution & precedence.** Loaded KV becomes a `PropertySource`. Standard Spring precedence applies: more specific wins — app-specific over `application`, profile-specific over non-profile. These sit in the Environment alongside `application.yml`, system props, env vars (which still outrank Config-imported sources per Spring's ordering rules for imported config). **Live refresh.** Spring Cloud Consul Config can **watch** the KV prefix (`spring.cloud.consul.config.watch.enabled`, with `watch.delay`). It uses Consul's blocking queries (long-poll) to detect changes; on change it fires a `RefreshEvent`, re-reads KV, and re-binds `@RefreshScope`/`@ConfigurationProperties` beans — so you can change a value in Consul and have running apps pick it up without redeploy. You can also manually trigger via the Actuator `refresh` endpoint. **Gotchas.** - Getting the prefix/context wrong means Spring silently finds nothing — verify keys are under `config/<exact-app-name>/`. - With `KEY_VALUE`, deeply nested keys map by replacing `/` with `.`; mismatches with `@ConfigurationProperties` names are a common bug. - `fail-fast` (default true) makes the app fail to start if Consul is unreachable — good for prod, annoying for local dev (set `spring.cloud.consul.config.fail-fast=false` or use `optional:consul:`). - Secrets: KV is not encrypted at rest by Spring; use Consul ACLs/encryption or Vault for secrets rather than plain KV. - Only `@RefreshScope`/`@ConfigurationProperties` beans re-bind on refresh; plain `@Value` in singleton beans won't update. **When to use.** Choose Consul Config when you already run Consul (unify discovery + config in one tool), want live KV-driven refresh, and don't need a separate Config Server. For strong secret management pair it with Vault.
- You changed a key in Consul KV but the running app didn't pick it up. Why?Either watch isn't enabled, or the bean isn't refreshable — only @RefreshScope / @ConfigurationProperties beans re-bind on a RefreshEvent. A plain @Value in a singleton is set once at construction and won't update until restart.
- KEY_VALUE format vs YAML format — trade-offs?KEY_VALUE stores one property per key (fine-grained, easy to change one value, but verbose and nesting is by path). YAML stores a whole document under one key (readable, structured, but you edit the blob and diffs are coarser).
saying these in an interview costs you the question
- Thinking @Value fields auto-refresh without @RefreshScope
- Confusing the config prefix (config/) with the discovery catalog
- Assuming KV stores secrets encrypted by default