Embedded Postgres for Spring Boot Tests
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
If your Spring Boot tests need real PostgreSQL behavior, an embedded Postgres instance is often a better fit than H2 compatibility mode. It gives you PostgreSQL-specific SQL behavior, types, and migration realism without depending on a shared external database. The main decision is whether embedded Postgres is the best tradeoff for your environment or whether Testcontainers is a better modern default.
Why Use Embedded Postgres At All
The usual reason is test fidelity. H2 is fast, but it does not behave exactly like PostgreSQL, so database-related bugs can slip through. Embedded Postgres narrows that gap by running a real PostgreSQL engine locally during tests.
That makes it useful for:
- repository integration tests
- migration verification
- SQL behavior that depends on PostgreSQL semantics
- CI environments where Docker is unavailable or undesirable
If Docker is easy to use in your team, Testcontainers is often the stronger choice today. But embedded Postgres remains useful when you want a lighter local dependency story.
A Typical Setup Pattern
One common pattern is to start the embedded database once for the test class and feed its JDBC settings into Spring Boot dynamically.
Then a Spring Boot test can inherit from that base and use the real PostgreSQL-backed DataSource.
Example Repository Test
This kind of test is much closer to production behavior than an H2-backed substitute.
Schema Management Still Matters
Embedded Postgres gives you a PostgreSQL engine, but it does not remove the need for schema management discipline. You should still run the same Flyway or Liquibase migrations that production uses.
That way your test database becomes a real compatibility check for the schema, not just a convenient place to persist rows temporarily.
Embedded Postgres Versus Testcontainers
A practical comparison looks like this:
- embedded Postgres: simpler local dependency story, no Docker required
- Testcontainers: closer to production packaging, easier version pinning, broader ecosystem support
If your team already uses Docker heavily in CI, Testcontainers is often the more future-proof path. If Docker availability is inconsistent or restricted, embedded Postgres can still be the easier solution.
Test Scope Matters
Do not run a full embedded Postgres-backed context for every tiny unit test. Use it for integration tests where the database behavior is actually part of what you are verifying. Pure business-logic tests should still run without Spring or a database whenever possible.
That separation keeps the suite fast and makes failures easier to localize.
Common Pitfalls
- Using embedded Postgres for every test in the project, including tests that do not care about persistence behavior.
- Forgetting to run real migrations and therefore missing schema drift problems.
- Treating embedded Postgres as identical to production while ignoring version mismatches.
- Choosing H2 for PostgreSQL-specific features and then discovering SQL differences too late.
- Ignoring Testcontainers as an alternative when Docker-based infrastructure is already standard in the team.
Summary
- Embedded Postgres is useful when tests need real PostgreSQL behavior without a shared external database.
- It is a stronger fit than H2 when PostgreSQL-specific SQL and migrations matter.
- Feed the embedded database connection details into Spring Boot dynamically during tests.
- Run the same migrations you use in production so tests verify real schema behavior.
- Prefer embedded Postgres or Testcontainers intentionally based on your team's environment and tooling constraints.
Related reading
- Embedded Redis for Spring Boot
- EmbeddedCassandra Cannot run unit tests
- Enable binary mode while restoring a Database from an SQL dump
- Enable hibernate filter globally with spring-boot spring-data
- Enable HAL serialization in Spring Boot for custom controller method
- Enable HTTP2 with Tomcat in Spring Boot
- EmbeddedKafka how to check received messages in unit test
- Emberjs - How to test promises and other async behavior?

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.