The Correct Way to Set Up Multiple Databases in Spring Boot
(Without Losing Your Sanity or Breaking Production)
A practical, real-world guide to configuring multiple databases in Spring Boot — based on mistakes, lessons, and production scars.
The first time I had to configure multiple databases in Spring Boot, I thought, “How hard can it be?”
Two datasources. Two URLs. Some configs. Done… right?
Wrong.
What followed was a week of cryptic errors, circular dependencies, mysteriously missing repositories, and one very memorable moment when production connected to the wrong database. That incident aged me at least three years.
If you’ve ever reached this point — where a simple app suddenly needs PostgreSQL and MySQL, or a legacy Oracle DB alongside a shiny new service — this article is for you.
Let’s talk about the correct, production-safe way to set up multiple databases in Spring Boot — the way I wish someone had explained to me earlier.
Why Multiple Databases Happen (Even If You Didn’t Plan For It)
No one starts a project saying, “Let’s complicate this with multiple databases.” It just… happens.
Some very real reasons:
- You’re migrating from a legacy monolith to microservices
- Reporting or analytics lives in a separate DB
- One database handles transactions, another handles reads
- Regulatory constraints (hello, banking 👋)
- Third-party systems you don’t control
In my case? A loan processing system where customer data lived in PostgreSQL, but credit bureau data was stored in Oracle. Mixing them was not optional.
The Biggest Mistake Most Developers Make
Let me say this clearly:
Multiple databases are not just multiple URLs in
application.yml.
If you copy-paste datasource configs and hope Spring magically figures things out, you’ll run into:
- Repositories bound to the wrong database
EntityManagerconflicts- Transactions behaving… creatively
- Debug sessions that make you question your career
Spring Boot is powerful — but only when you are explicit.
Mental Model First: How Spring Thinks About Databases
Before touching code, understand this:
Each database needs:
- Its own DataSource
- Its own EntityManagerFactory
- Its own TransactionManager
- Its own package of entities
- Its own package of repositories
If any of these overlap incorrectly, chaos follows.
Think of each database as a mini Spring app inside your app.
Step 1: Separate Your Domains (This Matters More Than Config)
Before YAML. Before annotations.
Structure your code properly.
Example:
com.example.app
├── userdb
│ ├── entity
│ ├── repository
│ └── config
└── auditdb
├── entity
├── repository
└── configThis separation:
- Makes intent obvious
- Prevents accidental cross-wiring
- Saves hours of debugging later
I learned this the hard way — after both databases tried to manage the same entity class.
Step 2: Define Multiple Datasources (Explicitly)
No magic. No guessing.
application.yml
spring:
datasource:
userdb:
url: jdbc:postgresql://localhost:5432/user_db
username: user
password: pass
driver-class-name: org.postgresql.Driver auditdb:
url: jdbc:mysql://localhost:3306/audit_db
username: audit
password: pass
driver-class-name: com.mysql.cj.jdbc.DriverNotice something important?
❌ No spring.datasource.url
✅ Everything is namespaced
Step 3: Create DataSource Beans (One Per DB)
@Bean
@ConfigurationProperties("spring.datasource.userdb")
public DataSource userDataSource() {
return DataSourceBuilder.create().build();
}And again for audit DB.
Yes, it feels repetitive.
Yes, it’s necessary.
Clarity beats cleverness every time.
Step 4: EntityManagerFactory (Where Most People Mess Up)
This is where things usually go sideways.
Get Things I Broke in Production’s stories in your inbox
Join Medium for free to get updates from this writer.
Each DB needs:
- Its own
EntityManagerFactory - A clearly defined entity package
@Bean
public LocalContainerEntityManagerFactoryBean userEntityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("userDataSource") DataSource dataSource) { return builder
.dataSource(dataSource)
.packages("com.example.app.userdb.entity")
.persistenceUnit("userdb")
.build();
}That persistenceUnit name?
It matters more than you think—especially when debugging.
Step 5: Transaction Managers (Don’t Share These)
One transaction manager per database.
@Bean
public PlatformTransactionManager userTransactionManager(
@Qualifier("userEntityManagerFactory") EntityManagerFactory emf) {
return new JpaTransactionManager(emf);
}If you skip this step, Spring will try to be “helpful.”
It won’t be.
Step 6: Enable Repositories (With Surgical Precision)
This annotation decides everything:
@EnableJpaRepositories(
basePackages = "com.example.app.userdb.repository",
entityManagerFactoryRef = "userEntityManagerFactory",
transactionManagerRef = "userTransactionManager"
)Read it slowly.
Spring now knows:
- Which repositories belong to which DB
- Which entities to scan
- Which transactions to use
This is where your system becomes stable.
Step 7: One Primary Database (Choose Wisely)
If your app has a “main” database, mark it:
@Primary
@Bean
public DataSource userDataSource() { ... }Why?
Because frameworks, libraries, and auto-configurations expect a default.
Without this, weird things start happening — usually at runtime.
Transactions Across Multiple Databases (Hard Truth)
Let’s talk about the elephant in the room.
Spring @Transactional does NOT magically work across multiple databases.
If you need:
- True atomic transactions across DBs
You’re entering distributed transaction territory.
Options:
- Two-phase commit (JTA) — complex, slow
- Event-driven eventual consistency — practical
- Saga pattern — production-friendly
In most real systems?
Eventual consistency wins.
I’ve seen teams attempt JTA under pressure.
I’ve never seen them enjoy it.
Testing Multiple Databases (Please Don’t Skip This)
What works locally can fail in CI.
Best practices:
- Use Testcontainers for each DB
- Don’t mock repositories blindly
- Verify actual connections and transactions
The first time you catch a cross-database bug in tests instead of prod…
you’ll thank yourself.
Common Pitfalls (From Real Production Bugs)
Here’s my personal hall of shame:
- Reusing entity packages across DBs
- Forgetting
@EnableJpaRepositories - One
TransactionManagerfor everything - Relying on auto-configuration
- Naming beans inconsistently
- Assuming order doesn’t matter (it does)
If this article saves you from even one of these — mission accomplished.
When You Should Rethink Multiple Databases
Sometimes the correct solution is… not doing this at all.
Reconsider if:
- Databases share most tables
- You only need logical separation
- Performance isn’t a real issue
A single database with schemas can be cleaner than two databases with chaos.
Architecture is about trade-offs, not trends.
Final Thoughts (What I Wish I’d Known Earlier)
Setting up multiple databases in Spring Boot isn’t hard because it’s complex.
It’s hard because:
- Spring gives you too much freedom
- Auto-configuration hides important details
- Tutorials skip real-world nuance
Once you understand the mental model, everything clicks.
And suddenly, it’s not scary anymore.
Call to Action
If you’ve:
- Fought with multiple datasources
- Broken prod (or almost did)
- Learned something the hard way
👉 Clap, share, or drop a comment with your story.
I read every single one — and we all learn faster together.
And if you want a follow-up on multi-database transactions, Flyway setups, or real banking-grade architectures — just say the word.









