Skip to content

Instantly share code, notes, and snippets.

@dcramer
Created May 28, 2025 00:00
Show Gist options
  • Save dcramer/71e2b3cd7110eae469a516467c39fead to your computer and use it in GitHub Desktop.
Save dcramer/71e2b3cd7110eae469a516467c39fead to your computer and use it in GitHub Desktop.
Drizzle vitest

vitest ✕ drizzle test-db plugin — mini-prd

tl;dr

ship an oss add-on that:

  1. spins up a fresh test db (or schema) on first run.
  2. reuses it if current drizzle schema hash hasn’t changed.
  3. wraps every spec in a savepoint + rollback by default (== super fast).
  4. lets any spec flip to “real tx, then truncate” via a tiny ctx flag.

no bespoke wrappers; we piggyback on vitest’s built-in test context.


api shape

// vitest.setup.ts
import { setupTestDb, useTestDb } from 'drizzle-vitest';

// one-time boot + cache check (fns are async, so top-level await in ESM)
await setupTestDb({
  schema: drizzleSchema,
  url: process.env.TEST_DATABASE_URL,
});
// global hook – default = savepoint
import { beforeEach } from 'vitest';
import { useTestDb } from 'drizzle-vitest';

beforeEach(async (ctx) => {
  // ctx is vitest’s TestContext; we just extend it
  await useTestDb(ctx); // mode: 'savepoint'
});
// inside a spec that needs real tx nesting / ddl
import { test } from 'vitest';

test('heavy ddl stuff', async (ctx) => {
  // switch this test to truncate mode on the fly
  await ctx.$db.mode('truncate');
  // … run crazy migrations …
});

how it works (high level)

  • automatic creationsetupTestDb hashes compiled drizzle schema; if no cached db or hash mismatch, it migrates a fresh db.
  • savepoint strategyuseTestDb(ctx) opens a txn, sets a savepoint; afterEach rolls back to it, keeping connection warm.
  • truncate strategy – same hook, but instead of a savepoint we just record table names and truncate cascade them in afterEach.
  • ctx plumbing – vitest passes a mutable TestContext as the first arg to every beforeEach/test; we augment it with ctx.$db so users can opt-in per spec.

code typings (skim)

// drizzle-vitest.d.ts
import { TestContext } from 'vitest';

declare module 'vitest' {
  interface TestContext {
    $db: {
      mode: (m: 'savepoint' | 'truncate') => Promise<void>;
      client: ReturnType<typeof drizzle>;
    };
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment