Conversation
flamboh
added this pull request to stack #118
September 25, 2026 10:46
- Add an infra/ workspace with an Alchemy v2 stack (alchemy and @alchemy.run/frontend-frameworks 2.0.0-beta.79, effect 4.0.0-rc.117): a D1 database with apps/web/drizzle migrations and a SvelteKit website bound to it as DB. Prod keeps the names atlantis-db and atlantis, adopts the wrangler-created worker, and retains both on destroy. Other stages get suffixed names. - Add deploy:cloudflare, plan:cloudflare, and destroy:cloudflare root scripts, and cover infra in lint, typecheck, and CI. - Remove wrangler.jsonc, the wrangler deploy and d1 scripts, adapter-cloudflare, and wrangler from apps/web. Alchemy injects its own adapter at deploy time. - Upgrade drizzle-kit and drizzle-orm to 1.0.0-rc.5 and convert the migrations to the v1 directory layout that Alchemy reads. - Load cloudflare:workers lazily and keep it external so kit's route analysis can run in Node, and reject the d1 driver under vite serve. - Patch the published SvelteKit adapter to use generateServerInstance, backporting the upstream fix for kit 3.0.0-next.27. - Document Alchemy deploys, migrations, Time Travel, and the first prod deploy.
flamboh
force-pushed
the
stack/alchemy-cloudflare
branch
from
September 27, 2026 04:48
55d3c34 to
17393d6
Compare
This was referenced Sep 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Warning
🤖 Claude Opus 5.5 on behalf of Oliver. This changes how production deploys. Production cutover is pending. Do not deploy the
prodstage until the cutover below is done.ELI5
The Cloudflare setup is now a TypeScript program (Alchemy) instead of a wrangler config file. Any copy of the site, such as a throwaway test copy, can be created and deleted with one command.
Flows to exercise
Setup: a Cloudflare API token and account ID exported as
CLOUDFLARE_API_TOKEN/CLOUDFLARE_ACCOUNT_ID, and a small verified SQLite database to seed from.bun run deploy:cloudflare --stage <you>(e.g.alice-dev). Expectatlantis-<you>andatlantis-db-<you>, all migrations applied, and a printed worker URL. Seed the D1 database, open the URL, and check a dataset page. Thenbun run destroy:cloudflare --stage <you>removes both.apps/web/srcrebuilds and uploads.bun run plan:cloudflare --stage alice_devfails withInvalid stage 'alice_dev'. … for example 'alice-dev'.Stage names are lowercase letters, digits, and single hyphens. Note that Alchemy's default stage (live_$USER) is rejected, so always pass--stage.bun run --cwd apps/web db:generateon an unchanged schema reportsNo schema changes, nothing to migrate.Decisions and edge cases
prodkeepsatlantis/atlantis-db, and destroyingprodretains both. Other stages get a-<stage>suffix. Stage names are validated because the old_→-mapping letalice_devandalice-devshare resources; with D1 adopt-by-name, destroying one could delete the other's database.1.0.0-rc.5-ab785fc, the build Alchemy pins, because Alchemy rejects the old_journal.jsonlayout. Migration SQL is byte-identical. The converted snapshots stored table-qualified CHECK expressions ("t"."col" > 0) while the new serializer emits unqualified ones ("col" > 0), sodb:generatesaw every CHECK as changed and emitted a migration rebuilding all six tables that have CHECKs. The snapshots now store the unqualified form; a test runsdrizzle-kit generateagainst a copy of the migrations and fails if it emits anything.planincluded, may offer to create or upgrade that store;plandoes not change the stage's worker or database.wrangler.jsonc, the wrangler deploy andd1:*scripts, and adapter-cloudflare (Alchemy injects its own adapter).@alchemy.run/frontend-frameworksbackports its upstream fix for kit3.0.0-next.27. Drop it on the next beta.alchemy devcan't providecloudflare:workersunder Node, so D1 testing means deploying a personal stage.vite devfails clearly if asked for D1.bun run --cwd apps/web previewstill rebuilds with SQLite and serves it (from feat(web)!: migrate to SvelteKit 3 and Vite 8 with build-time DB driver #115). The Playwright suite runsbuild:web(D1) and thenpreview, so every e2e run covers that path on this layer too.Production cutover (pending)
Not done in this PR.
atlantis-dbholds an older schema with an emptyd1_migrationstable, so a plain deploy would fail withtable datasets already exists. Plan:bunx wrangler@4.141.0 d1 time-travel info atlantis-db._cf_*.bun run plan:cloudflare --stage prod(database adopted, worker taken over in place, nothing replaced or deleted), thenbun run deploy:cloudflare --stage prod. Migrations run on the empty database.Rollback:
bunx wrangler@4.141.0 d1 time-travel restore atlantis-db --bookmark=<bookmark>. The same status and steps are indocs/user/operations.md.Follow-ups
Verification
Automated:
bun run format,lint,typecheck,test:web,test:infra(stage validation),test:e2e, landing lint, andbuild:landingpass;db:generateproduces no migration.Earlier manual checks (before the review fixes): a throwaway stage applied migrations, was seeded from a public sample dataset, and served
/, a dataset page, and six API routes byte-identical to local SQLite. An unchanged redeploy was a no-op, destroy removed the stage, and a read-only prod plan showed adopt/in-place takeover with nothing replaced or deleted.Remaining manual: re-run flow 1 with a hyphenated stage name, and the production cutover itself.
Claude Opus 5.5 · Claude Code (T3 Code)