What versions & operating system are you using?
System:
OS: Windows 11 10.0.26200
CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
Memory: 1.06 GB / 15.71 GB
Binaries:
Node: 24.18.0 - C:\Users\Grady\.vite-plus\js_runtime\node\24.18.0\node.EXE
npm: 11.16.0 - C:\Users\Grady\.vite-plus\js_runtime\node\24.18.0\npm.CMD
pnpm: 10.32.1 - C:\Users\Grady\.vite-plus\package_manager\pnpm\10.32.1\pnpm\bin\pnpm.CMD
npmPackages:
@cloudflare/vite-plugin: ^1.47.0 => 1.47.0
@cloudflare/vitest-pool-workers: ^0.18.8 => 0.18.8
wrangler: ^4.114.0 => 4.114.0
Please provide a link to a minimal reproduction
|
const names = fs |
|
.readdirSync(migrationsPath) |
|
.filter((name) => name.endsWith(".sql")); |
Describe the Bug
readD1Migrations() reads only *.sql files sitting directly in the directory it is given. It does not handle the nested <timestamp>_<name>/migration.sql layout that D1 added support for in May via migrations_pattern, so for a project using that layout it returns an empty array and applyD1Migrations() then applies nothing.
I've linked the source line rather than a repro repo, because the failure is entirely inside the reader — there's no interaction between components to reproduce, just a few lines of Wrangler config against one line of source, both inline below.
Setup
Wrangler config using the nested layout:
On disk — this is drizzle-kit's default output shape:
drizzle/
20260101000000_init/
migration.sql
snapshot.json
Steps to reproduce
wrangler d1 migrations apply example-db --local — reads and applies the migration.
- In
vitest.config.ts:
const migrations = await readD1Migrations("./drizzle");
console.log(migrations.length); // 0
applyD1Migrations() therefore applies nothing, and every test fails against an empty database.
Same directory, same Wrangler config, two different answers from the same toolchain.
Cause
packages/vitest-pool-workers/src/pool/d1.ts (permalinked above):
const names = fs
.readdirSync(migrationsPath)
.filter((name) => name.endsWith(".sql"));
A single non-recursive read, so a directory of per-migration subdirectories matches nothing. This matches only migrations_pattern's default value of ${migrations_dir}/*.sql.
Expected
readD1Migrations() reads the same migrations Wrangler applies.
Honouring migrations_dir / migrations_pattern from the Wrangler config the pool is usually already pointed at (via wrangler.configPath) would keep the test path and the deploy path from drifting. Globbing one level deeper would also fix the immediate problem.
Context
migrations_pattern shipped on May 29, 2026, explicitly to support this layout:
So Wrangler gained first-class support for the Drizzle layout two months ago, and the Workers Vitest integration's migration reader — the officially documented way to apply migrations in tests — cannot read it. Following the D1 docs to configure a Drizzle project leaves you with a test suite that runs against an empty database.
Related, smaller
Finding zero migrations returns [] silently, which is what makes this expensive to diagnose — the first symptom is no such table pointing at your own query, several layers from the cause. readD1Migrations() already throws a TypeError when migrationsPath isn't a string, so throwing when it finds nothing to apply would be consistent with its existing behaviour, and an empty migration set is never what the caller wanted.
Also adjacent, and more directly tied to the fix — the sort immediately below the code above:
names.sort((a, b) => {
const aNumber = parseInt(a.split("_")[0]);
const bNumber = parseInt(b.split("_")[0]);
return aNumber - bNumber;
});
This is safe today, because wrangler d1 migrations create always produces NNNN_name.sql and parseInt always succeeds. If nested layouts are read and names become paths relative to migrations_dir — per the D1 docs, e.g. 0001_init/migration.sql — that guarantee no longer holds: a directory without a numeric prefix gives NaN on both sides, and a comparator returning NaN leaves the ordering implementation-defined. Migration order isn't cosmetic, so it may be worth pinning explicitly as part of whatever the fix turns out to be.
Finally, unrelated to the bug itself but in the same area and cheap to fix: the JSDoc on applyD1Migrations (types/cloudflare-test.d.ts#L183-L184) and the Test APIs reference both say to call readD1Migrations() from the @cloudflare/vitest-pool-workers/config package, which is no longer in the exports map. The configuration reference already shows the correct root-package import.
Please provide any relevant error logs
Error: D1_ERROR: no such table: users: SQLITE_ERROR
❯ D1DatabaseSessionAlwaysPrimary._sendOrThrow cloudflare-internal:d1-api:146:19
❯ cloudflare-internal:d1-api:97:27
Every test in the project fails this way. Nothing in the output mentions migrations, the migrations
directory, or the fact that zero were applied.
What versions & operating system are you using?
Please provide a link to a minimal reproduction
workers-sdk/packages/vitest-pool-workers/src/pool/d1.ts
Lines 20 to 22 in afaecee
Describe the Bug
readD1Migrations()reads only*.sqlfiles sitting directly in the directory it is given. It does not handle the nested<timestamp>_<name>/migration.sqllayout that D1 added support for in May viamigrations_pattern, so for a project using that layout it returns an empty array andapplyD1Migrations()then applies nothing.I've linked the source line rather than a repro repo, because the failure is entirely inside the reader — there's no interaction between components to reproduce, just a few lines of Wrangler config against one line of source, both inline below.
Setup
Wrangler config using the nested layout:
On disk — this is drizzle-kit's default output shape:
Steps to reproduce
wrangler d1 migrations apply example-db --local— reads and applies the migration.vitest.config.ts:applyD1Migrations()therefore applies nothing, and every test fails against an empty database.Same directory, same Wrangler config, two different answers from the same toolchain.
Cause
packages/vitest-pool-workers/src/pool/d1.ts(permalinked above):A single non-recursive read, so a directory of per-migration subdirectories matches nothing. This matches only
migrations_pattern's default value of${migrations_dir}/*.sql.Expected
readD1Migrations()reads the same migrations Wrangler applies.Honouring
migrations_dir/migrations_patternfrom the Wrangler config the pool is usually already pointed at (viawrangler.configPath) would keep the test path and the deploy path from drifting. Globbing one level deeper would also fix the immediate problem.Context
migrations_patternshipped on May 29, 2026, explicitly to support this layout:migrations_pattern— "You can now pointwrangler d1 migrations applyat a nested migrations layout — such as the one produced by Drizzle (migrations/0001_init/migration.sql)"migrations/0001_init/migration.sql), setmigrations_patternto the glob that matches your layout"migrations_patternSo Wrangler gained first-class support for the Drizzle layout two months ago, and the Workers Vitest integration's migration reader — the officially documented way to apply migrations in tests — cannot read it. Following the D1 docs to configure a Drizzle project leaves you with a test suite that runs against an empty database.
Related, smaller
Finding zero migrations returns
[]silently, which is what makes this expensive to diagnose — the first symptom isno such tablepointing at your own query, several layers from the cause.readD1Migrations()already throws aTypeErrorwhenmigrationsPathisn't a string, so throwing when it finds nothing to apply would be consistent with its existing behaviour, and an empty migration set is never what the caller wanted.Also adjacent, and more directly tied to the fix — the sort immediately below the code above:
This is safe today, because
wrangler d1 migrations createalways producesNNNN_name.sqlandparseIntalways succeeds. If nested layouts are read and names become paths relative tomigrations_dir— per the D1 docs, e.g.0001_init/migration.sql— that guarantee no longer holds: a directory without a numeric prefix givesNaNon both sides, and a comparator returningNaNleaves the ordering implementation-defined. Migration order isn't cosmetic, so it may be worth pinning explicitly as part of whatever the fix turns out to be.Finally, unrelated to the bug itself but in the same area and cheap to fix: the JSDoc on
applyD1Migrations(types/cloudflare-test.d.ts#L183-L184) and the Test APIs reference both say to callreadD1Migrations()from the@cloudflare/vitest-pool-workers/configpackage, which is no longer in the exports map. The configuration reference already shows the correct root-package import.Please provide any relevant error logs
Every test in the project fails this way. Nothing in the output mentions migrations, the migrations
directory, or the fact that zero were applied.