How would you design a Config Server that maps different applications to different git repositories and combines multiple backends? What ordering rules apply?
answer
- git.repos + pattern = route apps to repos; git.uri = fallback
- {application}/{profile}/{label} placeholders = one repo, many apps
- composite = ordered list of typed backends (git+vault)
- aggregate ordering drives precedence; client merges first-wins
- watch latency, ownership, deterministic precedence
basics
~20 sUse pattern-based git repos (spring.cloud.config.server.git.repos) to route apps to specific repositories by name pattern, and the composite backend to combine sources like git plus Vault. Property sources from all matched repos are aggregated in configured order, most-specific first.
solid answer
~40 sFor per-app routing, configure spring.cloud.config.server.git.repos as a map of named entries, each with a pattern (e.g. 'payments*' or 'app/profile' patterns) and its own uri/searchPaths/label. A request whose {application} matches a pattern is served from that repo, with the top-level git.uri as the fallback default. To combine heterogeneous backends — git for general config, Vault for secrets — use spring.cloud.config.server.composite as an ordered list, each entry typed (git, vault, native, jdbc...). All matched property sources are aggregated into one Environment; ordering follows the composite list and per-source specificity, and clients still merge first-wins. Placeholders like {application}, {profile}, {label} in uri/searchPaths let one physical repo host many apps. The key design tensions are precedence determinism across repos, per-request latency (each backend is hit), caching, and clear ownership boundaries so teams control their own config repo.
code
java · 31 lines// --- Pattern-matched repos: route apps to team-owned git repos ---
// spring:
// cloud:
// config:
// server:
// git:
// uri: https://github.com/acme/config-default # fallback
// repos:
// payments:
// pattern: 'payments*'
// uri: https://github.com/acme/payments-config
// search-paths: '{application}'
// locked-prod:
// pattern: '*/prod'
// uri: https://github.com/acme/prod-config
// default-label: main
// --- Composite: git (config) + vault (secrets), ordered ---
// spring:
// cloud:
// config:
// server:
// composite:
// - type: git
// uri: https://github.com/acme/config-repo
// search-paths: '{application}'
// - type: vault
// host: vault.internal
// port: 8200
// kv-version: 2
// Property sources aggregate in list order; client merges first-wins.go deeper
Awareness that a Config Server can point at more than one repo is enough.
Know git.repos patterns route by app name and placeholders let one repo host many apps.
Explain composite backends, aggregate precedence ordering, and combining git with Vault for secrets.
Architect multi-team/multi-repo topologies with deterministic precedence, latency/HA planning, ownership boundaries, and the shorthand-vs-composite constraint.
**Two distinct mechanisms — don't conflate them.** **1. Pattern-matched git repos (routing within the git backend).** Under `spring.cloud.config.server.git.repos` you define named sub-repositories, each with a `pattern` and its own `uri`, `search-paths`, `default-label`, and credentials. The pattern matches the request's `{application}` (and optionally `/{profile}`), e.g.: - `payments*` → the payments team's repo, - `*/prod` → a locked-down prod repo. The top-level `spring.cloud.config.server.git.uri` is the **default/fallback** used when no pattern matches. Patterns support simple wildcards and app/profile forms (`{application}/{profile}`). This lets one Config Server front many team-owned repos with clean ownership boundaries. **2. Placeholders (one repo, many apps).** Independently, you can embed `{application}`, `{profile}`, `{label}` in `uri` or `search-paths`. `search-paths: '{application}'` makes one repo serve `payments/`, `orders/` subfolders; a placeholder in the `uri` can even resolve a repo per application. Placeholders reduce the number of physical repos; patterns route across physical repos. They're often used together. **3. Composite backends (combining different backend types).** `spring.cloud.config.server.composite` is an **ordered list** where each entry declares a `type` (`git`, `vault`, `native`, `jdbc`, `redis`) and its settings. The `CompositeEnvironmentRepository` calls each in order and concatenates their `PropertySource`s into a single `Environment`. Typical use: git for non-secret config plus Vault for secrets. Rules and caveats: - With composite you **must** give every entry a `type`; you can't also use the single-repo shorthand simultaneously. - Ordering in the list determines the relative precedence of each backend's sources (earlier entries' sources appear ahead), and within each backend the usual most-specific-first ordering applies. The client still resolves first-wins. - Duplicate keys across backends resolve by that aggregate order — make it explicit so secrets from Vault deterministically win or lose as intended. **Design considerations at scale.** - **Precedence determinism.** Across multiple repos/backends, be deliberate about order so an override always lands where expected; document it. - **Latency & availability.** Each request may touch several backends; a slow/unavailable git remote or Vault directly impacts client startup. Use `clone-on-start`, force-pull tuning, and rely on the server's git caching. Consider server-side HA (multiple instances behind a LB) since it's a startup dependency. - **Ownership & blast radius.** Pattern-routed per-team repos limit who can change what and shrink the blast radius of a bad commit; a single mega-repo is simpler but couples teams. - **Consistency.** Different repos on different branches can drift; standardize `default-label` and branch conventions. - **Security.** Per-repo credentials/keys; keep secrets in Vault, not git, and compose them. **Gotchas.** - Mixing the single `git.uri` shorthand with composite config throws — pick one style. - An overly broad pattern (`*`) can shadow more specific ones; order and specificity matter. - Placeholder repos that don't exist for a given app cause failures at request time, not startup. - Forgetting that composite ordering, not alphabetical or accidental, drives which backend wins. **Why principals get asked this.** It probes whether you can architect config for many teams/environments with predictable precedence, acceptable latency, and clean ownership — not just wire a single git.uri.
- You configure both the top-level git.uri shorthand and a composite list. What happens?It fails to start — you must choose one style. With composite, every entry needs an explicit type and you don't also use the single-repo shorthand.
- How do you make one physical git repo serve dozens of applications without a folder explosion?Use placeholders in search-paths (or the uri), e.g. search-paths: '{application}', so each app's request resolves its own subfolder; combine with per-team pattern repos only when you need separate ownership/permissions.
saying these in an interview costs you the question
- Mixing the single git.uri shorthand with composite config (it errors).
- Assuming repo precedence is alphabetical rather than configured list order.
- Ignoring that each backend adds per-request latency to client startup.