Spin up ephemeral, isolated PostgreSQL instances for testing.
Zero configuration — works out of the box even if PostgreSQL is not installed on your machine. The library automatically downloads and caches a lightweight prebuilt PostgreSQL bundle (~30 MB) on first use.
- Python 3.8+
- Internet access on first run (to download the prebuilt binary bundle)
The package is currently available only from GitHub (not yet on PyPI).
pip install git+https://github.com/piotr-rudnik/embedded-postgres.gitOr add to your project's dependencies::
# pyproject.toml
[project]
dependencies = [
"embedded-postgres @ git+https://github.com/piotr-rudnik/embedded-postgres.git",
]from embeddedpostgres import EmbeddedPostgres
import psycopg2
with EmbeddedPostgres() as pg:
conn = psycopg2.connect(pg.url())
cur = conn.cursor()
cur.execute("SELECT 1")
print(cur.fetchone()) # (1,)
cur.close()
conn.close()
# Server is automatically stopped and data directory cleaned up.Add this to your conftest.py::
import pytest
from embeddedpostgres import EmbeddedPostgres
@pytest.fixture(scope="session")
def postgres():
pg = EmbeddedPostgres()
pg.start()
yield pg
pg.stop()Then use it in tests::
import psycopg2
def test_something(postgres):
conn = psycopg2.connect(postgres.url())
cur = conn.cursor()
cur.execute("CREATE TABLE items (id serial PRIMARY KEY, name text)")
cur.execute("INSERT INTO items (name) VALUES ('widget')")
cur.execute("SELECT name FROM items")
assert cur.fetchone()[0] == "widget"
cur.close()
conn.close()embeddedpostgres ships with ready-made fixtures. Import them in your conftest.py::
pytest_plugins = ["embeddedpostgres.fixtures"]Then use in tests::
import psycopg2
def test_with_session_server(postgres_session):
"""Reuse a single server across the whole test session."""
conn = psycopg2.connect(postgres_session.url())
...
def test_with_isolated_database(postgres):
"""Get a fresh database URL inside the shared server."""
conn = psycopg2.connect(postgres)
...postgres_session— one server for the whole test session (fastest)postgres— a fresh database per test function inside the shared server (good balance of speed and isolation)
- System lookup — checks your
$PATHand common install locations for a local PostgreSQL. - Auto-download — if nothing is found, downloads the correct prebuilt bundle from Maven Central (
zonkyio/embedded-postgres-binaries). - Cache — extracts the bundle to
~/.cache/embeddedpostgres/<version>/and reuses it forever. - Boot —
initdbcreates a temp data directory,postgresstarts on a random free port. - Cleanup — on
stop()or context-manager exit the server shuts down and temp data is removed.
First download takes ~10–30 s depending on your connection. Every subsequent start is ~0.6 s.
| Parameter | Default | Description |
|---|---|---|
version |
"16.0.0" |
PostgreSQL version to download (e.g. "18.3.0") |
port |
random free port | TCP port to bind the server |
database |
"postgres" |
Default database name |
username |
"postgres" |
Superuser name |
password |
"postgres" |
Superuser password |
data_dir |
temp directory | Where to store the data cluster |
pg_bin_dir |
None |
Path to your own initdb/postgres binaries |
# Use PostgreSQL 18.3.0
with EmbeddedPostgres(version="18.3.0") as pg:
...
# Use your own local binaries
pg = EmbeddedPostgres(pg_bin_dir="/opt/postgres/16/bin")
pg.start()Downloaded binaries are cached in:
~/.cache/embeddedpostgres/(Linux / macOS)%LOCALAPPDATA%\embeddedpostgres\(Windows, viaplatformdirsif added)
Set XDG_CACHE_HOME to override the cache directory.
pg = EmbeddedPostgres(version="16.0.0", port=25432, database="myapp_test")
pg.start()
pg.url() # -> "postgresql://postgres:postgres@127.0.0.1:25432/myapp_test"
pg.dsn() # -> dict for psycopg2.connect(**pg.dsn())
pg.stop()Context-manager support::
with EmbeddedPostgres() as pg:
url = pg.url()
...For advanced use you can manage the binary cache directly::
from embeddedpostgres import PostgresBinaryManager
mgr = PostgresBinaryManager(version="16.0.0")
bin_dir = mgr.get_bin_dir() # Path object to the bin/ directoryPrebuilt binaries are available for:
- Linux — amd64, arm64v8, i386
- macOS — amd64 (Intel), arm64v8 (Apple Silicon)
- Windows — amd64, i386
If your platform is unsupported the library raises RuntimeError with a clear message.
Add embedded-postgres to your pyproject.toml dependencies::
dependencies = [
"embedded-postgres @ git+https://github.com/piotr-rudnik/embedded-postgres.git",
]For development / test-only usage::
[project.optional-dependencies]
test = [
"embedded-postgres @ git+https://github.com/piotr-rudnik/embedded-postgres.git",
"pytest",
]Users running your tests do not need PostgreSQL installed — the library handles everything automatically.
MIT