Sitemap

The Correct Way to Set Up Multiple Databases in Spring Boot

5 min readDec 31, 2025

--

(Without Losing Your Sanity or Breaking Production)

Press enter or click to view image in full size

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
  • EntityManager conflicts
  • 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
└── config

This 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.Driver

Notice 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.

Press enter or click to view image in full size

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 TransactionManager for 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.

--

--

Things I Broke in Production
Things I Broke in Production

I write real stories about backend systems breaking in production. Spring Boot, CI/CD, microservices, and outages — plus how teams actually fix them.