Data Access Testing With @testcontainers A blog post demonstrates using the @testcontainers/postgresql package to run data access tests against an isolated PostgreSQL 18 Alpine database spun up in Docker, replacing the older pattern of transaction-wrapped test databases with try/finally rollbacks. The author notes the approach requires Docker locally, which GitHub Actions' Ubuntu runners already include, and shows schema setup via the drizzle-kit push command from the Drizzle ORM toolchain. The post argues tests are worth writing for database logic doing real work, but not for basic CRUD. With AI now writing the overwhelming majority of our code, testing and verification have never been more important. We probably all know how to write unit tests with something like Jest https://jestjs.io/ or Vitest https://vitest.dev/ , or even verify that our front-end code behaves correctly using something like RTL. But writing tests against data access code has always been harder. Unit tests should be fast and isolated; introducing an external database works against both goals. Historically, a common approach would be to have a test database, and, for each test, add a try block and begin a transaction, possibly with a READ UNCOMMITTED isolation level depending on the database and test, insert data, verify, and in the finally block rollback the transaction. The downsides of this approach should be obvious. The complexity is high, as is the likelihood of different, concurrent tests interfering with each other while running on the same test database. That’s actually a very reasonable question, and the answer, as it often is, is “it depends.” If your data access code is basic CRUD, inserting records and then reading them back, then no, you probably don’t need to bother writing tests for code with such low complexity. But if your database logic is doing real work, consider tests to verify it behaves correctly. This post will show you how. Let’s get started. These days we have better options than hacking around transactions; we have Docker https://www.docker.com/ . Docker lets us spin up virtually anything in a completely isolated container, do what we want, and then let the container vanish into the ether. And to help utilize Docker for this very use case, there’s a nifty family of packages called @testcontainers . There are a number of modules within that family, and for this post we’ll be looking at @testcontainers/postgresql . You’ll need Docker running locally on your machine. Install and start Docker Desktop or a suitable alternative if it isn’t already. If you’re worried about CI/CD, don’t. GitHub Actions’ Ubuntu runners include Docker, so these tests will run just fine there. You’ll likely lean on your agent of choice for this, but know that setting up your database is as simple as this: js const postgres = await new PostgreSqlContainer "postgres:18-alpine" .start ; To get the URL to the database in that container, it’s just as simple: postgres.getConnectionUri ; You’ll probably want to access this object in both the beforeAll hook of your tests to set things up, as well as the afterAll hook to tear it down. To declare this variable before assignment, without losing any typings, just lean on TypeScript a bit: js let postgres: Awaited