Testcontainers
Use this skill when work touches disposable Docker containers for integration tests: databases, brokers, cloud emulators, Compose stacks, wait strategies, Ryuk cleanup, or CI container runtimes.
Workflow
- Inspect the local Testcontainers surface before changing code:
- Language and package versions (
testcontainers,@testcontainers/*, Javaorg.testcontainers:*, Python extras, Gomodules/...). - Container runtime: Docker Desktop, Colima, Podman, OrbStack, Rancher, DinD, or Testcontainers Cloud.
- Test runner lifecycle: Vitest/Jest global setup, JUnit
@Container, pytest fixtures, GoCleanupContainer. - Existing modules vs hand-rolled generic containers; networks; Compose; reuse flags.
- Language and package versions (
- Refresh current official docs when versions are unclear, the language API differs, or the work touches CI/runtimes/Cloud. Start from source-map.md.
- Route the work to the focused references:
- Node/TypeScript core, waits, networks, modules, runners: node-core.md.
- Java, Python, Go, and other languages: languages.md.
- Cross-language modules catalog: modules-catalog.md.
- Env vars, CI, runtimes, Ryuk, reuse, security: ci-runtimes-ops.md.
- Prefer the project's language and existing module packages. Do not introduce a second language binding.
- Verify at the narrowest useful boundary (one module + client), then the suite lifecycle.
Core Judgment
- Prefer official modules over
GenericContainer/DockerContainerwhen a module exists for the dependency. - Always resolve runtime host + mapped port (
getHost()/getMappedPort()/ language equivalents). Never hardcodelocalhost:5432or fixed host ports. - Pin image tags (
postgres:16.3,redis:7.4). Avoid floatinglatestin CI. - Prefer copy into container over bind mounts (bind mounts break under DinD/remote Docker).
- Use networks + aliases for multi-container DNS. Avoid fixed container names and hostnames.
- Pick wait strategies deliberately: listening ports (default), log message, HTTP, healthcheck, or composite. On Colima/Rancher, pair log/HC waits with listening-port waits.
- Keep Ryuk enabled in CI unless the environment cannot support it; if disabled, ensure another cleanup path.
- Enable reuse only on local developer machines (
withReuse/TESTCONTAINERS_REUSE_ENABLE). Do not rely on reuse in CI. - Reserve Testcontainers for integration/contract boundaries. Keep pure unit tests free of Docker.
- Match module majors to core (Node 12.x modules with
testcontainers@12; Java 2.xtestcontainers-*artifacts + BOM). - Throwaway credentials only. Never put production secrets in container env.
Language defaults
| Language | Core package | Prefer |
|---|---|---|
| Node/TS | testcontainers + @testcontainers/<svc> |
Modules + await using / reliable teardown |
| Java | org.testcontainers:testcontainers + BOM 2.x |
Modules + try-with-resources or JUnit @Container |
| Python | testcontainers[extras] |
Modules + context managers / fixtures |
| Go | testcontainers-go + modules/<svc> |
testcontainers.Run + CleanupContainer(t, …) |
Verification
Prefer repository-owned commands. For meaningful Testcontainers work, cover the relevant subset:
- Confirm Docker (or Cloud agent) is reachable before diagnosing test failures.
- Focused integration test: start module → connect with real client → assert one behavior → stop/cleanup.
- Multi-container / network / Compose smoke when those APIs changed.
- Wait-strategy failure modes: assert useful timeout errors, not hung suites.
- CI-shaped run when changing env vars, Ryuk, DinD, socket mounts, or Cloud setup.
- Parallelism check: random ports + no shared mutable container state unless suite-scoped by design.
- Snapshot/restore checks for Postgres modules (do not use database name
postgresfor snapshots).
Report which checks ran, which did not, and any runtime or package-version assumptions that remain.