Spring Cloud Bootstrapping: Config, Discovery & Setup from a Senior Dev
Learn to bootstrap Spring Cloud microservices with Config Server and Eureka.
20+ years shipping production Java in banking & fintech. Drawn from code that ran under real load.
- ✓Java 17+
- ✓Spring Boot 3.x
- ✓Basic understanding of microservices architecture
- ✓Familiarity with Spring Boot application properties
- ✓Git (for Config Server repository)
- Use Spring Cloud Config Server for externalized configuration; avoid embedding config in JARs.
- Service discovery with Netflix Eureka is still solid for most teams; Consul is an alternative if you need health checking.
- Start with Spring Initializr and add spring-cloud-starter-config, spring-cloud-starter-netflix-eureka-client.
- Always use bootstrap.yml for bootstrap-phase config; application.yml is loaded later.
- Never hardcode service URLs; use discovery client or load-balanced RestTemplate.
Imagine you're building a city of services (microservices). Each building needs blueprints (configuration) and a phone book (service discovery). Spring Cloud Config Server is the blueprint office where all buildings get their plans. Eureka is the phone book that tells each building where the others are. Bootstrapping is the process of setting up the blueprint office and phone book before any building can function.
| Chrome | Firefox | Safari | Edge |
|---|---|---|---|
| ✓ | ✓ | ✓ | ✓ |
After 15 years of building microservices—starting with the Netflix stack when it was still called 'Cloud Native'—I've seen every possible way to screw up a Spring Cloud bootstrap. I've debugged production outages at 2 AM because someone put a database URL in application.yml instead of bootstrap.yml. I've watched teams spend weeks trying to figure out why their services couldn't find each other, only to realize they forgot to annotate their main class with @EnableDiscoveryClient.
Here's the hard truth: most teams get the initial setup wrong. They treat bootstrap like an afterthought, copy-paste configs from tutorials, and then wonder why their system falls apart when they add a third service. This article is the bootstrapping guide I wish I had when I started. We'll cover configuration management with Spring Cloud Config Server, service discovery with Eureka, and the critical setup patterns that separate production-grade systems from hobby projects.
You'll learn why bootstrap.yml exists, how to avoid circular dependencies between config and discovery, and what the official docs conveniently omit about real-world deployments. If you're building microservices with Spring Cloud, this is your starting point—get it wrong and everything downstream suffers.
Why Bootstrap.yml Exists (And Why Most Devs Get It Wrong)
Spring Cloud's bootstrap context is loaded before the main application context. This is not a quirk—it's a necessity. The bootstrap phase is responsible for setting up the infrastructure your application needs to even start: connecting to a Config Server, initializing encryption, setting up service discovery bindings.
I've seen countless developers try to put spring.cloud.config.uri in application.yml, only to watch their services fail with 'Could not resolve placeholder'. The bootstrap context doesn't have access to application.yml—it hasn't been loaded yet. That's why bootstrap.yml exists.
Here's the load order, straight from the Spring Cloud docs (but buried in a footnote): 1. Bootstrap context loads bootstrap.yml (or bootstrap.properties) 2. Bootstrap context connects to Config Server (if configured) 3. Config Server returns application.yml (or profile-specific) 4. Main application context loads
If you need a property during step 2, it must be in bootstrap.yml. This includes: - spring.cloud.config.uri - spring.cloud.config.username/password - spring.cloud.config.fail-fast - Encryption keys (spring.cloud.config.server.encrypt.*) - Service discovery bootstrap (e.g., eureka.client.serviceUrl.defaultZone if fetched from Config)
Many teams also make the mistake of putting too much in bootstrap.yml. Keep it minimal—only properties needed to bootstrap. Everything else belongs in application.yml or Config Server files.
Setting Up Spring Cloud Config Server
The Config Server is the backbone of your microservice configuration. It centralizes all property files and serves them to clients on startup. Here's how to set it up properly.
First, create a new Spring Boot application with the Config Server dependency. Add @EnableConfigServer to your main class. Then configure the backend where config files are stored. Git is the most common choice for production—it gives you versioning, auditing, and branching per environment.
Example application.yml for Config Server:
spring: cloud: config: server: git: uri: https://github.com/myorg/config-repo search-paths: '{application}' default-label: main
I strongly recommend using a private Git repository with SSH keys or HTTPS credentials. Never store secrets (passwords, API keys) in plain text in the config repo. Use encryption with a symmetric key or integrate with a vault like HashiCorp Vault.
One production gotcha: if your Git repo is not accessible during startup, the Config Server will fail to initialize. Use a local filesystem backend for development, but always use Git for staging and production. Also, consider setting spring.cloud.config.server.git.clone-on-start=false to avoid cloning the entire repo on startup—instead, it clones lazily on first request.
For high availability, run multiple Config Server instances behind a load balancer. They all read from the same Git repo, so they are stateless. Set spring.cloud.config.server.git.force-pull=true to ensure they always fetch the latest version.
Service Discovery with Eureka: What the Official Docs Won't Tell You
Eureka is the most battle-tested service discovery solution in the Spring Cloud ecosystem. It's simple, reliable, and works well for most teams. But the official docs gloss over several critical details.
First, never use Eureka's self-preservation mode in development. It's designed for production to prevent cascading failures, but in dev it can cause instances to remain registered after they've stopped. Disable it with eureka.server.enableSelfPreservation=false.
Second, set appropriate renewal thresholds. The default lease renewal interval is 30 seconds, and the lease expiration duration is 90 seconds. For high-traffic services, you might want shorter intervals. But be careful—too short can cause unnecessary churn.
Third, always configure Eureka client with fetchRegistry=true and registerWithEureka=true (these are defaults). If you have a service that doesn't need to be discovered (like a gateway that knows all routes statically), you can set registerWithEureka=false.
Here's a common mistake: forgetting to add @EnableDiscoveryClient on the main class. Without it, the service won't register with Eureka. Also, ensure spring.application.name is set—Eureka uses it as the service ID.
For high availability, run multiple Eureka servers that peer with each other. Each server registers with the others, creating a cluster. Use DNS or a load balancer to point clients to the cluster.
Bootstrap Order: Config Server vs Eureka – The Chicken-and-Egg Problem
Here's a classic bootstrap puzzle: your services need to connect to Config Server to get the Eureka URL, but they also need Eureka to find the Config Server. This circular dependency can be solved in several ways.
Option 1: Hardcode the Config Server URI in bootstrap.yml. This is the simplest and most common approach. The Config Server is a known infrastructure component, so its URL rarely changes. Use a DNS name or load balancer to make it resilient.
Option 2: Use a separate discovery-first bootstrap. Some teams configure Eureka URL directly in bootstrap.yml, then fetch all other config from Config Server via discovery. This works but adds complexity.
Option 3: Use Spring Cloud Config's native discovery support. Set spring.cloud.config.discovery.enabled=true and provide the Eureka URL in bootstrap.yml. The Config Server client will first register with Eureka, then query Eureka to find the Config Server. This is elegant but adds a startup dependency on Eureka.
I recommend Option 1 for most teams. It's straightforward and avoids the extra startup complexity. For large deployments with many microservices, Option 3 can reduce duplication but requires careful orchestration.
One more thing: if you're using Config Server to serve Eureka configuration, ensure that the Config Server itself is not dependent on Eureka. Otherwise, you have a circular dependency at the infrastructure level.
What the Official Docs Won't Tell You About Bootstrap Configuration
The Spring Cloud documentation is comprehensive, but it hides several critical details that only come to light after you've been burned in production.
1. Bootstrap.yml is not the only bootstrap file. Spring Cloud also loads bootstrap.properties and bootstrap-{profile}.yml. You can use profile-specific bootstrap files to configure different Config Server URIs per environment. For example, bootstrap-dev.yml can point to a local Config Server, while bootstrap-prod.yml points to the production one.
2. Property precedence is tricky. During bootstrap, properties from bootstrap.yml have the highest precedence, but after the main context loads, application.yml properties can override them. If you need a bootstrap property to absolutely not be overridden, use spring.cloud.config.override-none=true.
3. Encryption context is separate. If you use Spring Cloud Config's encryption features, the encryption key must be available during bootstrap. This means either hardcoding it in bootstrap.yml (bad practice) or setting it as an environment variable or system property. The official docs don't emphasize this enough.
4. Fail-fast and retry are not enabled by default. Without fail-fast, if the Config Server is unreachable, the application will start with default values or fail later with confusing errors. Always set spring.cloud.config.fail-fast=true and configure retry settings.
5. Bootstrap context is not destroyed. Some developers assume that the bootstrap context is discarded after the main context loads. It's not—it remains as a parent context. This can cause issues if you have beans with the same names in both contexts. Use @Primary or explicit bean names to avoid conflicts.
Integrating with Other Spring Cloud Components
Once you have Config Server and Eureka running, you can integrate other Spring Cloud components. Here's a quick overview of how they fit into the bootstrap picture.
Spring Cloud Gateway: The API gateway uses service discovery to route requests to registered services. Configure it with spring.cloud.gateway.discovery.locator.enabled=true to automatically create routes based on Eureka service IDs. No need to hardcode URLs.
Feign Clients: Feign (or OpenFeign) integrates with Eureka and Ribbon (or Spring Cloud LoadBalancer) to make inter-service calls. Annotate your Feign client interface with @FeignClient(name = "payment-service") and it will use discovery to find instances.
Resilience4j Circuit Breaker: Integrate with Feign or RestTemplate to add circuit breakers. Configure fallback methods and thresholds via Config Server properties.
Spring Cloud Bus: Used to propagate config changes across services. It requires a message broker (RabbitMQ or Kafka). The bus configuration is typically in application.yml, not bootstrap, because it's not needed for startup.
Spring Cloud Sleuth: Distributed tracing. Add spring-cloud-starter-sleuth and it will automatically add trace IDs to logs. No bootstrap changes needed.
All these components rely on the bootstrap foundation you've set up. A solid bootstrap ensures that your services can find each other, load the right configuration, and handle failures gracefully.
The Bootstrap YAML That Took Down Production
- Always define Config Server URI in bootstrap.yml, not application.yml.
- Treat bootstrap.yml as sacred—it's loaded before anything else.
- Add a startup check that validates bootstrap configuration.
- Use Spring Cloud Config's fail-fast and retry settings to avoid silent failures.
- Never refactor bootstrap properties into application files without understanding the load order.
curl -v http://config-server:8888/myapp/defaultjava -jar myapp.jar --debug| File | Command / Code | Purpose |
|---|---|---|
| bootstrap.yml | spring: | Why Bootstrap.yml Exists (And Why Most Devs Get It Wrong) |
| ConfigServerApplication.java | @SpringBootApplication | Setting Up Spring Cloud Config Server |
| EurekaServerApplication.java | @SpringBootApplication | Service Discovery with Eureka |
| bootstrap-dev.yml | spring: | What the Official Docs Won't Tell You About Bootstrap Config |
| bootstrap.yml (complete example) | spring: | Integrating with Other Spring Cloud Components |
Key takeaways
Interview Questions on This Topic
Explain the bootstrap phase in Spring Cloud. What is its purpose and how does it differ from the main application context?
Frequently Asked Questions
20+ years shipping production Java in banking & fintech. Drawn from code that ran under real load.
That's Spring Cloud. Mark it forged?
5 min read · try the examples if you haven't