Self-hosted service
ory/dockertest avatar
ory/dockertest

ory/dockertest v4: ephemeral Docker containers for Go integration tests

Write better integration tests! Dockertest helps you boot up ephermal docker images for your Go tests with minimal work.

4,527 stars270 forksGoApache-2.0

At a glance

What is it?
Dockertest boots throwaway Docker images from inside Go tests, and version 4 adds automatic container reuse plus a lighter Docker client. It fits Go projects that need real databases in CI, not mocks.
Who is it for?
Adopt ory/dockertest v4 if your Go tests need a real Postgres, MySQL, Redis or MongoDB and you are willing to run a Docker daemon in CI. Do not adopt it if your tests are not written in Go, or if you cannot give the runner a working Docker socket and enough disk.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 75 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The mocking problem ory/dockertest was built to remove

Testing a service that talks to a database usually means either mocking the driver or stubbing the data layer. The README states the case plainly: making slight changes to the schema implies rewriting at least some, if not all mocks, and the same goes for API changes in the DBAL. Every schema migration turns into a maintenance pass over test doubles that were never the thing under test.

Dockertest takes the other route. It boots a real container from Docker Hub or from a Dockerfile, hands your test the connection details, and lets the container disappear when the test finishes. The README frames Docker as the right system for this because containers start in a few seconds and can be killed on completion.

The audience is narrow and specific: Go developers writing integration tests for services that depend on third-party infrastructure. The examples directory ships tests for Postgres, MySQL, Cassandra, CockroachDB, Redis, MinIO, MongoDB and Mountebank, which is a fair map of the intended use. If your project is not in Go, this library is not for you, and the repository makes no claim otherwise.

How pools, resources and reuse keys fit together

The central object is a pool. In test code you create one with dockertest.NewPoolT, which the README describes as auto-cleanup with t.Cleanup(). For non-test code there is dockertest.NewPool, which returns an error and requires a manual Close call. The pool holds the Docker client and the wait configuration.

From the pool you call RunT or Run to start a container, and you get back a resource. The resource exposes GetHostPort, which takes a container port such as "5432/tcp" and returns the host-side address your test connects to. That single call is the bridge between the container and your application code.

The v4 change worth understanding is reuse. The README says version 4 introduces automatic container reuse, making tests significantly faster by reusing containers across test runs. The default reuse key is "repository:tag", and WithReuseID overrides it. WithoutReuse disables the behaviour for a single run. This is a design trade-off, not a free win: a reused container keeps whatever state the previous run left behind, so tests that assume a clean database on every start will behave differently under v4 than they did under v3. The README points to UPGRADE.md for the complete migration guide rather than spelling out the consequences inline.

The second v4 change is the client. The go.mod lists github.com/moby/moby/client and github.com/moby/moby/api rather than the older Docker client stack, and the README describes this as a lightweight docker client that reduces third party dependencies significantly. The dependency list in go.mod is short enough to audit by hand, which is unusual for a library that talks to a container runtime.

Installing ory/dockertest v4 and running a Postgres container

Installation is a single go get against the v4 module path:

bash
go get github.com/ory/dockertest/v4

The README's quick start is a test function that creates a pool, starts Postgres 14, reads the mapped port and waits for readiness. The pool is created with an empty string as the second argument, and the container is configured through functional options:

go
package myapp_test

import (
    "testing"
    "time"

    dockertest "github.com/ory/dockertest/v4"
)

func TestPostgres(t *testing.T) {
    pool := dockertest.NewPoolT(t, "")

    postgres := pool.RunT(t, "postgres",
        dockertest.WithTag("14"),
        dockertest.WithEnv([]string{
            "POSTGRES_PASSWORD=secret",
            "POSTGRES_DB=testdb",
        }),
    )

    hostPort := postgres.GetHostPort("5432/tcp")
}

After RunT returns, hostPort holds the host-side address for the container's 5432 port, and the README's comment shows the connection string shape: postgres://postgres:secret@hostPort/testdb. The container is registered for cleanup through the pool, so it goes away when the test ends.

The next step is waiting. A container that has started is not necessarily a container that accepts connections, so the README wraps the readiness check in pool.Retry with a timeout:

go
err := pool.Retry(t.Context(), 30*time.Second, func() error {
    // try connecting...
    return nil
})
if err != nil {
    t.Fatalf("Could not connect: %v", err)
}

You supply the body of the retry function, usually a Ping against the database. If it never succeeds inside the window, Retry returns an error and the test fails with your message. The 30 second figure is the README's example, not a hard limit; WithMaxWait sets the pool-level maximum wait to something like 2*time.Minute.

Custom reuse, explicit port bindings and the options that bite

The option list is long, and a few entries matter more than the rest. WithName sets the container name, which is convenient for debugging but collides if two runs pick the same name. WithMounts takes bind mounts in "host:container" or "host:container:mode" form, so a relative host path resolves against the working directory of the test binary rather than the repository root. WithPortBindings takes a network.PortMap and hands you explicit control over host ports, which is what you want when the default random mapping is not enough.

For anything the typed options do not cover, WithContainerConfig and WithHostConfig accept a modifier function over the underlying container.Config and container.HostConfig. The README's example sets StopTimeout, StopSignal and a Healthcheck with an interval, timeout and retry count. This is the escape hatch, and it is also the point where the abstraction stops protecting you: once you are writing against container.Config directly, a change in the underlying Moby types is your problem, not the library's.

WithReuseID deserves attention. The default key is "repository:tag", which means a container started with WithTag("14") and a container started with no tag at all (defaulting to "latest") will not share a container even though they are the same repository. If two test packages use the same image and tag, they share a container by default. That is the source of the speedup and the source of cross-test interference in equal measure.

Where ory/dockertest is the wrong tool

The first limitation is language. This is a Go module with a Go 1.25.5 directive in go.mod. Nothing in the repository suggests bindings for other languages, and the search results that pair dockertest with Python do not reflect what this repository ships. If your test suite is in Python or Java, you are looking at the wrong project.

The second is the Docker dependency itself. The README has a dedicated section on running in CI with sub-sections for GitHub Actions and GitLab CI, and the GitLab section splits shared runners from custom group runners. That split exists because shared runners may not give you a usable Docker socket. A library that starts containers cannot work on a runner that will not let you start containers.

The third is disk. The README's troubleshooting section leads with a single entry: out of disk space. Every image you pull and every container you leave behind consumes space on the machine running the tests, and reuse makes that worse rather than better because containers are deliberately kept alive between runs.

The fourth is state. If your test asserts that a table is empty at the start, or that a migration runs from scratch, automatic reuse works against you. WithoutReuse exists for exactly this, and the option is a signal that the default is not universally correct.

Finally, there is a category of test that should never touch this library. Pure functions, parsers, and anything with no external service dependency gain nothing from a container and pay the startup cost anyway.

How this differs from Testcontainers

The obvious comparison is Testcontainers, which is the phrase people actually search for alongside this project. Both start real containers for integration tests. The difference is in the shape of the API and the scope of the project.

Testcontainers is a family of libraries across multiple languages, with a module system that models specific services: a Postgres module knows how to build the connection string, a Kafka module knows how to wait for the broker. Dockertest stays closer to the Docker primitives. You name an image, set environment variables, map a port and write your own readiness check inside pool.Retry. There is no service catalog to learn and no module to wait for when a new database version appears, but there is also no module doing the connection-string work for you.

The dependency footprint differs too. Dockertest v4's go.mod pulls in the Moby client and API packages plus a short indirect list. A multi-language test framework carries more surface area by construction.

Neither approach is universally better. If you want a typed, per-service API and you use several languages across your repositories, Testcontainers gives you consistency. If you are in Go, want to name an image and control the container config directly, and prefer a small dependency tree, dockertest is the more direct route. The reuse model is the other axis: dockertest v4 reuses containers across test runs by default, and you should check whether the equivalent behaviour in your alternative is opt-in or absent.

Licence, maintenance and the cost of upgrading from v3

The repository is Apache-2.0. The Makefile includes a licenses target that runs a license checker over the dependency tree, and the package.json declares license-checker as a dev dependency, so the project checks its own dependency licences as part of its tooling. That tells you the maintainers care about the question; it does not tell you your own obligations, which depend on how you distribute your software and are a matter for your own review.

The repository is not archived, and the last push was on 2026-07-17. The most recent release is v4.0.0, published on 2026-04-14, preceded by v4.0.0-beta.4 and v4.0.0-beta.3 in March 2026. Version 4 is the current line, and the default branch is named v4.

The upgrade cost is real and the project acknowledges it. The README states that version 4 introduces automatic container reuse and a lightweight docker client, and directs readers to UPGRADE.md for the complete migration guide. The API itself changed shape: the quick start uses NewPoolT and RunT rather than the v3 style, and options such as WithTag, WithEnv and WithCmd replace whatever configuration mechanism v3 used. The README does not document rollback, and it does not describe a compatibility shim for v3 call sites. If you have a large existing suite on v3, treat the migration as a code change with a test run behind it, not a version bump. The go.mod directive of Go 1.25.5 is a hard floor for anyone on an older toolchain.

Editorial conclusion

Adopt ory/dockertest v4 if your Go tests need a real Postgres, MySQL, Redis or MongoDB and you are willing to run a Docker daemon in CI. Do not adopt it if your tests are not written in Go, or if you cannot give the runner a working Docker socket and enough disk. Before committing, verify that your CI runner exposes the Docker socket, check the disk-space section of the README, and read UPGRADE.md to see what the v3 to v4 move changes in your existing pool code.

Frequently asked questions

How does ory/dockertest compare with Testcontainers?

Both start real Docker containers for integration tests. Dockertest keeps you close to the Docker primitives: you name an image, set environment variables, map a port and write your own readiness check inside pool.Retry, while Testcontainers is a multi-language family with per-service modules. Dockertest v4 reuses containers across test runs by default, keyed on "repository:tag".

How do I install ory/dockertest for Go?

The README gives a single command: go get github.com/ory/dockertest/v4. The module path carries the v4 major version, and go.mod declares a Go 1.25.5 directive, so your toolchain needs to satisfy that.

How do I run Postgres in an ory/dockertest test?

The README's quick start creates a pool with dockertest.NewPoolT, starts the container with pool.RunT(t, "postgres", dockertest.WithTag("14"), dockertest.WithEnv(...)), then reads the mapped address with postgres.GetHostPort("5432/tcp"). Readiness is checked by passing a function to pool.Retry with a timeout.

What changed in ory/dockertest v4?

Version 4 introduces automatic container reuse, which the README says makes tests significantly faster by reusing containers across test runs, and a lightweight docker client that reduces third party dependencies. The README points to UPGRADE.md for the complete migration guide from v3.

Can I stop ory/dockertest from reusing a container?

Yes. The option list includes WithoutReuse, which disables container reuse for that run, and WithReuseID, which sets a custom reuse key instead of the default "repository:tag".

Official sources

  1. License: Apache-2.0
  2. ory/dockertest on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ory-dockertest.svg)](https://hysenlabs.com/projects/ory-dockertest)