Remove DB / Auth / Storage
Strips the template down to a frontend-only TanStack Start app by removing:
- Cloudflare D1 + Drizzle ORM (database)
- Cloudflare R2 (avatar storage)
- Better Auth (Google OAuth)
The Cloudflare Workers deployment is deliberately kept. Only the bindings
(D1, R2) and the auth vars leave wrangler.toml, so bun run deploy keeps
working the moment this procedure finishes.
What else stays: the app shell, shared UI (src/components/ui, header,
mode-toggle, theme-provider), the sample home page, and the oxlint / oxfmt /
tsc / knip / vitest toolchain.
Preconditions
git statusis clean, and the work happens on a dedicated branch (the change set is large).
1. Delete source code
rm -rf src/lib/auth src/lib/drizzle src/lib/storage
rm -rf src/entities src/gateways src/server
rm -rf src/routes/api
rm -f src/routes/login.tsx src/routes/profile.tsx src/routes/auth.auth-code-error.tsx
rm -rf src/components/features/profile-page
rmdir src/components/features 2>/dev/null || true
rm -rf src/components/shared/header/auth-navigation src/components/shared/header/user-menu
rm -f src/test/cloudflare-workers-stub.ts
src/routeTree.gen.ts is gitignored and generated, so refresh it with
bun run generate-routes after deleting route files.
Two things above are easy to misread as deployment removals, and neither is one:
src/server/containscloudflare.live.ts, whose only job isimport { env } from "cloudflare:workers"to hand out the D1 / R2 / secret bindings. With no bindings left it has no callers. The Worker itself does not need it.src/test/cloudflare-workers-stub.tsexists only to satisfy the vitest alias for that import (step 3). It goes with it.
Do not delete src/ssr.tsx. It is the Worker entry that wrangler.toml#main
points at. It calls createStartHandler and touches no binding, so
it survives this procedure untouched, including its
satisfies ExportedHandler<CloudflareEnv> annotation, which still typechecks
after every binding is gone (wrangler types emits an empty CloudflareEnv
interface rather than omitting it, which was verified rather than assumed).
2. Fix auth-dependent UI
src/components/shared/header/header.tsx
Remove the user prop, the UserWithEmail / AuthNavigation imports, and the
similarity-ignore comment:
import { Link } from "@tanstack/react-router";
import { ModeToggle } from "@/components/shared/mode-toggle/mode-toggle";
export const Header = () => (
<header className="sticky top-0 z-50 bg-transparent backdrop-blur-md">
<div className="flex items-center justify-between px-6 py-6">
<div>
<h1 className="font-medium text-2xl">
<Link to="/">Title</Link>
</h1>
</div>
<div className="flex items-center gap-5">
<Link to="/" className="text-gray-400 text-sm">
Link1
</Link>
<Link to="/" className="text-gray-400 text-sm">
Link2
</Link>
<ModeToggle />
</div>
</div>
</header>
);
src/routes/__root.tsx
- Delete the
getCurrentUserFnimport and theloaderoption. - Delete
const { user } = useLoaderData({ from: "__root__" });and render<Header />without props.
src/routes/index.tsx
The sample home page hardcodes the stack and setup commands. Remove the
Better Auth and Drizzle ORM entries from the STACK array, and drop the
cp .env.local.example .env.local line from the "Get started" code snippet (the
env example file is deleted in step 4). Note: the step 7 residual grep will
not catch these, because "Better Auth" has a space and "Drizzle ORM" is
capitalized, so neither matches the better-auth / drizzle (lowercase,
case-sensitive) patterns. Fix them here explicitly.
Residual auth references
grep -rn "signIn\|signOut\|session\|getCurrentUserFn\|AuthNavigation\|UserMenu\|UserWithEmail" src/
Remove every hit individually.
3. Update build / test config
vite.config.ts needs no change, because the cloudflare() plugin is what builds
the Worker, and it stays.
vitest.config.mts: drop the cloudflare:workers alias
The alias only existed to stub that import for src/server/cloudflare.live.ts, which
step 1 deleted. Remove the alias block and the now-unused node:path import.
Keep the coverage block. It is the per-file 100% branch gate that AGENTS.md's
Testing section names this file as the home of, and dropping it retires that gate
silently. Inside it, remove the coverageExclude entry
"src/routes/api/auth.$.ts" and the comment above it, because step 1 deletes that
route. Then read the remaining entries against the tree step 1 leaves and drop any
other one that names a file it deleted.
tools/oxlint-plugins/arch-rules.js: prune the dead layer bans
LAYER_BANS encodes as import bans the layer order AGENTS.md's Rules section
names. Step 1 deletes every layer below routes, so a ban whose layer or
target names a deleted path has nothing left to protect.
Remove those entries together with the cases in arch-rules.test.ts that cover
them: vitest.config.mts holds this file at 100% branch coverage, so a pruned
ban with a surviving test, or the reverse, fails bun run test. If every ban
goes, the layer-boundaries rule and its entry in the plugin export go too.
When that happens, also remove "arch-rules/layer-boundaries": "error" from
vite.config.ts's lint.rules map, because the plugin export and that entry name the same
rule ID, so dropping only one half leaves the config pointing at a rule nothing
supplies.
Neither file under tools/oxlint-plugins/ is deleted. arch-rules.js also
carries the component and test-shape rules, style-rules.js is untouched by this
procedure, and vite.config.ts loads both by path under lint.jsPlugins, so removing
either file breaks the lint config for the whole fork.
knip.json
- Remove
"src/server/fn/**/*.ts"fromentry. - Remove
"src/server/cloudflare.live.ts"fromignore.
4. Config files
wrangler.toml: edit, do not delete
Delete the [[d1_databases]] and [[r2_buckets]] blocks. Keep name, main, compatibility_date, and compatibility_flags.
Delete the [secrets] block and the comment above it. Every name in its
required list is an auth secret this procedure removes, and naming a secret
there makes it required at deploy time, and docs/DEPLOYMENT.md carries that
contract. Leaving the block behind is the one edit in this step that breaks the
deployment this skill exists to keep: wrangler deploy would fail on secrets the
fork has no way to supply. When a fork introduces a secret of its own, the block
comes back carrying that name.
Leave compatibility_flags = ["nodejs_compat"] in place unless you have
verified nothing in the remaining build needs it. It is cheap to keep, and
removing it on a hunch is how a deploy breaks in production rather than locally.
Then regenerate the env types, as AGENTS.md's Generated types stay generated requires after this file changes:
bun run cf-typegen
Delete what is genuinely DB-only
rm -f drizzle.config.ts
rm -rf .wrangler # local D1 / R2 state
rm -f docs/DATABASE_SETUP.md
rm -f .env.local .env.local.example
worker-configuration.d.ts is kept, and so is the # cloudflare block in
.gitignore that lists it.
After deleting the env files, the only secrets path left is
wrangler secret put, which is where production secrets belong anyway.
docs/DEPLOYMENT.md stays and still describes it.
5. Update package.json
bun remove better-auth drizzle-orm drizzle-kit dotenv
wrangler and @cloudflare/vite-plugin stay, because they are the deployment rather than the
database.
Remove these scripts: db:generate, db:push, db:studio, db:pull,
db:push:local.
Keep everything else, explicitly including deploy, preview, and
cf-typegen.
After the knip run in step 8, remove any dependencies it now flags as unused.
Expected: zod and @hookform/resolvers (their last consumers were
src/entities/user and the profile form). react-hook-form, sonner, and
radix-ui stay, because src/components/ui/ still uses them.
6. Update docs / settings
Several documents still describe the removed stack. Read each one end to end
and strip every reference to the database, auth, and storage layer: D1, R2,
Drizzle, Better Auth, Google OAuth, BETTER_AUTH_*, and the deleted src/
paths.
No list of individual lines follows, for the reason AGENTS.md's Instruction
documents rule gives. Step 7's greps catch only references that contain a
matching literal, and README.md's quickstart copies the env example file this
procedure deletes without naming any of the terms.
Surfaces to go through: README.md, docs/DEPLOYMENT.md, docs/FORKING.md,
and .claude/settings.json.
Do not strip these while you are in there. They are the deployment, which this procedure keeps:
- README's
Hosting: Cloudflare Workersline and thessr.tsxentry in the project structure. docs/DEPLOYMENT.mditself and every link to it.- In
.claude/settings.json, thewrangler types/wrangler deploy/wrangler tail/wrangler secret:*entries. Remove onlywrangler d1 *,wrangler r2:*,drizzle-kit *, andbun run db:*. AGENTS.mdneeds no change at all, because the fork still runs on Cloudflare Workers.
Places where the right edit is not a deletion:
docs/DEPLOYMENT.md's シークレットのローテーション section loses its subject, not just some lines:BETTER_AUTH_SECRETandGOOGLE_CLIENT_SECRETare the only application secrets this template has, so once they go the table, its heading, both examplewrangler secret putlines, and the two paragraphs explaining better-auth's wiring and its fail-loud guard all go with them. Reduce the section to generic guidance:wrangler secret list|put|deletewith no named secrets, plus the ordering rule (register the new value, verify, then revoke the old one). That rule's procedure still holds, but its wording does not: it warns that reversing the order drops 認証 during the gap, and there is no auth left. Generalize the consequence to whatever consumes the secret. Step 7's grep is ASCII-only and will not flag that word. Finally, the section's closing paragraph, which points local secrets at the deleted env file, becomes "secrets go towrangler secret put".docs/DEPLOYMENT.md's rollback commands and their explanation survive. What goes is the 重要な限界 block after them (the D1-schema caveat and its three-step staged-migration list), which only matters when a database exists.docs/FORKING.mdsection 2 is entirely about swapping D1 / R2 resources, so it empties out, and it also holds the only pointer todocs/DEPLOYMENT.md. Move that pointer into section 1 and drop the section. Its headings are numbered, so renumber the survivors (3→2, 4→3) rather than leaving a gap. Section 4 (now 3) also ends by telling the reader to consult/remove-dbfor removing auth, which is circular advice for a fork that just ran it. Drop that sentence and the profile-feature deletion list with it.- Two documented rules stop applying and their homes have to say so.
.env.local.exampleanddocs/DATABASE_SETUP.mddescribe the standing exception that lets drizzle-kit'sCLOUDFLARE_API_TOKENsit on disk. Removing drizzle-kit closes that exception, so the wording goes with the files.
7. Residual reference check
Scope the grep to database, auth, and storage terms. Do not grep for
wrangler / cloudflare / CloudflareEnv, because those legitimately remain in
wrangler.toml, vite.config.ts, src/ssr.tsx, and package.json, and
treating them as leftovers is what leads to deleting the deployment by mistake.
grep -rn "better-auth\|BETTER_AUTH\|drizzle\|D1Database\|R2Bucket\|AVATARS_BUCKET\|d1_databases\|r2_buckets" \
src scripts tools package.json vite.config.ts vitest.config.mts knip.json wrangler.toml \
README.md AGENTS.md .claude/settings.json docs/DEPLOYMENT.md docs/FORKING.md
Read every hit and decide, because a hit is not automatically a leftover. This
grep reaches the eight literals above in the paths above and nothing else, so an
empty result carries no proof, which AGENTS.md's Instruction documents rule
states for a grep in general. One exclusion from the path list is deliberate:
generic infra checklists (e.g. .claude/skills/launch-checklist) keep their
generic D1 / R2 mentions.
Dead markdown links to the deleted database doc need no grep, because bun .claude/hooks/check-md-links.ts fails on any link whose target is gone, and
AGENTS.md's Verification before completion says when the Stop gate runs it.
What it cannot see is prose that names
the file without linking it, so check that separately:
grep -rn "DATABASE_SETUP" README.md AGENTS.md .claude/ docs/DEPLOYMENT.md docs/FORKING.md
Hits inside this skill file are its own instructions, not leftovers. The path discipline is the same as above and for the same reason: a dated record that cites the file describes what was true when it was written and must not be "fixed".
8. Verify
bun install
bun run generate-routes
bun run cf-typegen
bun run check
bun run test
bun run knip
bun run build
bun run dev # https://my-app.localhost (portless)
bun run preview # runs the built Worker on http://localhost:4173
typecheckerrors point at imports of deleted modules. Remove them.knipfindings point at now-unused dependencies/exports. Remove them (see step 5).previewpassing is the signal that the Worker build is still intact. If it fails, something in step 1 or 4 removed part of the deployment rather than the database.
Deploying (bun run deploy) should work unchanged against the same Worker name.
9. Commit
Split per the Commits discipline in AGENTS.md:
feat:remove the auth / profile / DB-access features (src/deletions +Header/__rootedits)chore:remove the D1 / R2 / Drizzle configuration (wrangler.toml bindings, drizzle.config.ts, vitest alias, knip, the local-DB scripts, the env files, anddocs/DATABASE_SETUP.md)chore:remove the DB / auth dependencies (package.json / bun.lock)docs:remove DB- and auth-related documentation. Stage every surface step 6 touched, each by its explicit path as that discipline requires:README.md,docs/DEPLOYMENT.md,docs/FORKING.md,.claude/settings.json,.env.local.exampleandwrangler.toml. A surface missing from this list is a surface left uncommitted.
Intermediate commits are not individually buildable (e.g. commit 1 deletes the vitest stub that commit 2's config change stops referencing), so verify on the final state.