How to Configure a DataSource Programmatically in Spring Boot
Learn how to configure a DataSource programmatically in Spring Boot.
20+ years shipping production Java in banking & fintech. Lessons pulled from things that broke in production.
- ✓Java 17+
- ✓Spring Boot 3.x
- ✓Basic understanding of Spring Boot auto-configuration
- ✓Familiarity with HikariCP or connection pooling concepts
- Use a @Configuration class with @Bean methods to define DataSource, JPA properties, and TransactionManager.
- Override spring.datasource.* properties by providing your own DataSource bean.
- For multiple databases, use @Primary and @Qualifier annotations.
- Always close the DataSource in @PreDestroy to avoid connection leaks.
- Test with Testcontainers to avoid hardcoded connection strings.
Think of a DataSource as the plumbing connecting your app to the database. Normally Spring Boot auto-plumbs for you, but sometimes you need custom pipes (e.g., for multiple databases or cloud secrets). Programmatic configuration is like manually installing those pipes instead of relying on the default setup.
Spring Boot's auto-configuration is a lifesaver—until it isn't. You drop a few lines in application.properties, and boom, you have a DataSource. But what happens when you need to connect to multiple databases, read credentials from a vault, or use a connection pool with specific tuning? The auto-configuration gets in the way.
I've seen countless teams struggle when they outgrow the magic. A fintech startup I consulted for had a production outage because their auto-configured HikariCP pool exhausted connections under load—they had no idea how to customize it programmatically. The default pool size of 10 was fine for dev, but in production with 200 concurrent users, it was a ticking bomb.
This article is for the developer who needs to take control. You'll learn how to configure a DataSource from scratch in Spring Boot, handle multiple databases, and avoid the pitfalls that the official docs gloss over. No fluff, just battle-tested patterns.
Why Go Programmatic?
Spring Boot's auto-configuration is great for simple apps, but it has limits. When you need to connect to multiple databases, use a custom connection pool, or load credentials from a secure vault, you have to take the wheel.
I've worked on a SaaS platform that needed separate databases for read and write operations. The auto-configuration could only handle one. We had to define two DataSources programmatically. Another time, a client required a connection pool with validation and leak detection—defaults weren't enough.
Programmatic configuration gives you full control. You can set pool sizes, timeouts, and even switch databases at runtime. The trade-off is more code and responsibility. But for production systems, it's often the right call.
Step-by-Step: Creating a Programmatic DataSource
Let's build a production-ready DataSource configuration. Start with a @Configuration class and a @Bean method that returns a HikariDataSource.
First, define the HikariConfig. Set the JDBC URL, username, password, and pool size. Then create the DataSource.
But wait—where do you put credentials? Hardcoding is a security risk. Use environment variables or a vault. Spring Boot's Environment can inject values via @Value or @ConfigurationProperties.
Here's a robust example:
Multiple DataSources: The Right Way
Handling multiple databases is where programmatic configuration shines. You define two DataSource beans, but you must mark one as @Primary and use @Qualifier for injection.
Here's the pattern: Create two @Bean methods, each returning a DataSource. Annotate the primary one with @Primary. Then, when injecting, use @Qualifier("nameOfBean").
But there's a gotcha: Spring Boot's auto-configuration for JPA will try to use the primary DataSource. For the second one, you need to create a separate EntityManagerFactory and TransactionManager.
Let's see it:
What the Official Docs Won't Tell You
The Spring Boot reference guide is comprehensive, but it leaves out some hard-earned lessons. Here are the gotchas I've encountered:
- Auto-configuration back off: If you define a single DataSource bean, Spring Boot's auto-configuration backs off. But if you define multiple, it still tries to configure a default EntityManagerFactory. You must explicitly disable JPA auto-configuration or provide your own.
- HikariCP defaults: The default maximumPoolSize is 10. In production, that's often too low. Also, connectionTimeout defaults to 30 seconds, which can cause long waits. Set both explicitly.
- DataSourceBuilder vs HikariConfig:
DataSourceBuilder.create().build() returns a HikariDataSource if HikariCP is on the classpath. But you lose fine-grained control. Use HikariConfig directly for production tuning. - @Primary is not optional: If you have multiple DataSources, you must mark one as @Primary. Otherwise, injection fails with 'NoUniqueBeanDefinitionException'.
- Closing the DataSource: Spring Boot does not automatically close programmatic DataSources. Use @PreDestroy on a @Bean method to call
close(). Otherwise, you leak connections on shutdown. - Transaction management: With multiple DataSources, you need separate transaction managers. Spring's @Transactional uses the primary one by default. Use @Transactional("transactionManagerName") to specify.
Testing Your DataSource Configuration
Never deploy a DataSource configuration without testing it. Use Testcontainers to spin up a real database in your tests. This catches issues like wrong URLs, missing drivers, or insufficient pool sizes.
Here's a test example:
The Case of the Vanishing Connections
- Never trust default pool sizes in production—profile your connection usage.
- Always set a connection timeout and leak detection threshold.
- Use @PreDestroy to close the DataSource gracefully.
- Monitor connection pool metrics via Actuator or JMX.
- Test under realistic load before going live.
Check application.properties for spring.datasource.urlVerify @Configuration class is scanned| File | Command / Code | Purpose |
|---|---|---|
| DataSourceConfig.java | @Configuration | Why Go Programmatic? |
| DatabaseConfig.java | @Configuration | Step-by-Step |
| MultiDataSourceConfig.java | @Configuration | Multiple DataSources |
| CleanupConfig.java | @Configuration | What the Official Docs Won't Tell You |
| DataSourceTest.java | @SpringBootTest | Testing Your DataSource Configuration |
Key takeaways
Interview Questions on This Topic
How do you configure a DataSource programmatically in Spring Boot?
Frequently Asked Questions
20+ years shipping production Java in banking & fintech. Lessons pulled from things that broke in production.
That's Hibernate & JPA. Mark it forged?
3 min read · try the examples if you haven't