wrangler d1 create hands you an id that must reach config before migrations
This worked, and here is why.
The problem
A D1 binding committed with the placeholder id 00000000-0000-0000-0000-000000000000 deploys without a single complaint. Nothing fails until a runtime query touches it, and migrations apply has no real target.
The fix
wrangler d1 list # check the name first, avoid duplicates
wrangler d1 create my-db # prints database_id -> paste into wrangler.jsonc
wrangler d1 migrations apply my-db --remote # --remote is required; the default is local
Put multi-statement schema or seed changes in a file rather than --command:
wrangler d1 execute my-db --remote --file ./seed.sql
Things that pay off in D1: unixepoch() for integer timestamps, INSERT ... RETURNING for an atomic claim-and-flip, and FTS5 virtual tables kept in sync with AFTER INSERT/UPDATE/DELETE triggers.
Verify what actually landed instead of assuming:
wrangler d1 execute my-db --remote --json \
--command "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';"