A production-minded TanStack Start foundation for new applications. It supplies reusable infrastructure while leaving domain models, product copy, analytics, authentication, databases, and deployment credentials to the application built on top.
- TanStack Start and React 19
- Nitro production output, ready for Vercel
- Tailwind CSS 4
- shadcn/ui on Base UI with Rhea, Mist, and Tabler icons
- TypeScript and Vitest
- Ultracite with type-aware Oxlint, Oxfmt, React Doctor, TanStack rules, and the vendored anti-slop Oxlint plug-in
- pnpm and Lefthook
- Impeccable skill support for Codex, Claude Code, and Cursor
Requirements: Node.js 24 and pnpm 11.24.0.
If pnpm is not installed yet, use pnpm's documented npm installer with the repository's exact pinned version:
npx get-pnpm 11.24.0pnpm install
pnpm devOpen http://localhost:3000.
Then work through the setup guide. It lists every value to replace, in order, and ends at a running application with no placeholder text.
After GitHub creates a repository from this template, open its Actions tab. If GitHub says workflows are not being run, click Enable Actions on this repository before expecting the tracked CI and CodeQL workflows to appear on pull requests. GitHub does not replay earlier repository events, so run the workflows manually or push another commit after enabling them.
GitHub does not copy repository settings from a template. This repository ships importable branch rulesets under .github/rulesets; apply them after the new repository exists and you have decided which deployment, if any, should gate merges.
The setup guide is written to be executed. Send this to your agent:
Set up this repository as my new project by following docs/template-setup.md. Start with the questions in step 1.
What the agent will do
- Ask seven questions in one batch: project and package name, a one-sentence description, the production origin, the host, whether to keep the example routes, whether brand assets are ready, and whether to apply the GitHub branch ruleset (including an optional deployment gate).
- Apply that identity to
package.json,src/lib/site-config.ts,public/manifest.json, andpublic/robots.txt. - Keep or remove the example routes, then reconcile the route inventory and navigation.
- Replace the logo, favicon, and social card, and retire the trademark notice.
- Set the Nitro preset when the host is not Vercel.
- If explicitly authorized, apply
.github/rulesets/default-branch.json; if the host is Vercel, apply.github/rulesets/vercel-preview.jsononly after a successful preview deployment and an exact environment-name check. - Rewrite
PRODUCT.md,DESIGN.md,AGENTS.md, and this README for the product. - Delete the template-only documents while keeping any adopted repository policy files.
- Run
pnpm validate, start the server, and confirm the new identity renders and any selected repository ruleset reports correctly.
Each step ends on a stated result, and most are checked by a command rather than by inspection, so the work is verifiable as it goes.
pnpm dev # Start the development server
pnpm fix # Apply safe Oxlint and Oxfmt fixes
pnpm check # Check lint, formatting, and type-aware rules
pnpm typecheck # Run TypeScript without emitting files
pnpm test # Run the Vitest suite once
pnpm build # Build the Nitro production output and prerender public routes
pnpm seo:verify # Inspect built metadata, schema, sitemap, robots, and SSR headings
pnpm start # Run an existing production build locally
pnpm validate # Run every CI and pre-push gatesrc/routesowns file-based routes and route-level metadata.src/components/uicontains shadcn primitives. Add more withpnpm dlx shadcn@latest add <component>.src/lib/site-config.tsis the single seam for public identity and canonical origin.src/lib/seo.tsbuilds consistent page metadata and JSON-LD from that config.src/lib/site-files.tsgeneratesrobots.txtandmanifest.jsonfrom the same config, so no file underpublic/restates the project's identity.src/lib/public-routes.tsclassifies every route aspublicorprivate. It is the prerender and sitemap inventory, and it is checked against the generated route tree at compile time.src/lib/server-runtime.tsholds the example server functions and the isomorphic environment helper.src/start.tsregisters global request middleware throughcreateStart.src/server.tsis the server entry. It swaps in srvx'sFastResponse, which is roughly a 5% throughput gain on Node hosts and a no-op on runtimes where srvx exports the platformResponse.src/routes/api/health.tsis an example server route that answers with JSON.scripts/verify-seo-output.mjsverifies the rendered production artifacts instead of trusting source configuration alone.docs/template-publishing.mdrecords the repository settings and rehearsal steps that cannot live in application code.tools/oxlint/anti-slopis vendored lint plug-in source fromdmmulroy/anti-slop.
TanStack Router generates src/routeTree.gen.ts. Do not edit it by hand.
Ultracite is the quality entry point. Oxlint owns linting and Oxfmt owns formatting and Tailwind class ordering. ESLint and Prettier are intentionally absent.
Lefthook formats and lints staged files before commit, then runs pnpm validate before push. Claude Code and Cursor format and lint the edited file after each edit. The tracked Impeccable skill adds UI-specific guidance and hooks for Codex, Claude Code, and Cursor. Vendored skill and plug-in source are excluded from application quality gates.
The files in .github/rulesets are policy artifacts, not active settings. A repository created from this template must import them separately. The baseline protects the default branch from deletion and force pushes, requires pull requests with resolved review conversations, allows squash and rebase merges, and requires the validate check. It starts with zero required approvals so a solo maintainer can use it; add an approval and code-owner review when the project has a review team.
With GitHub CLI authenticated as a repository administrator, run this once in the new repository:
repo=$(gh repo view --json nameWithOwner --jq .nameWithOwner)
gh api --method POST \
-H "Accept: application/vnd.github+json" \
"repos/$repo/rulesets" \
--input .github/rulesets/default-branch.jsonThe optional Vercel ruleset requires a successful deployment in the exact Preview environment. Apply it only after Vercel has produced that deployment; for a project-suffixed or custom environment, edit the environment name first. Other hosts should keep the baseline until their integration emits a stable GitHub deployment environment. See the ruleset notes for the full procedure and caveats.
The example uses https://example.com so a fresh clone builds successfully without pretending to own a production domain. Replace it before deployment in:
src/lib/site-config.tspublic/robots.txt
Add each public route to src/lib/public-routes.ts. The Nitro build prerenders that inventory and generates sitemap.xml; pnpm seo:verify checks the finished HTML for unique titles, descriptions, canonical URLs, social metadata, JSON-LD, and server-rendered headings.
/runtime demonstrates the server/browser boundary instead of describing it:
- Server functions in
src/lib/server-runtime.ts.getRenderSnapshotis aGETfunction called from a route loader.analyzeTextis aPOSTfunction whose.validatorstage rejects input before the handler runs. Handler bodies never reach the client bundle. - Isomorphic code.
createIsomorphicFnkeeps a server branch and a client branch behind one call, and each branch is stripped from the bundle it does not belong to. - Request middleware in
src/start.ts, which runs for every request the server handles, including server routes and server functions. It sets conservative security headers and rejects cross-site requests to server functions. A Content-Security-Policy is deliberately absent because a useful one depends on the application. - Server routes in
src/routes/api/health.ts, which answer with JSON rather than a document and are classifiedprivate.
Two behaviors are worth knowing before copying the pattern:
- A prerendered route's loader runs at build time to produce the shipped HTML and again on the server when the router revalidates after hydration. Loader output is not frozen at build time.
.validatoris the input boundary for a server function. This template ships no schema library, so the example validator is a plain function; a Standard Schema validator drops into the same seam.
A route that depends on browser APIs can opt out of server rendering with ssr: false or ssr: "data-only". No example route needs it, so the template does not use it.
Nitro is the deployment-agnostic layer, so a different host is a preset rather than a different build. It is registered once in vite.config.ts and every target shares the same pnpm build output. Nitro documents the full preset list.
Run pnpm validate before the first deployment and after changing public route metadata.
Import the repository and set Framework Preset to TanStack Start. The nitro() plugin is the server build layer underneath that preset and detects Vercel automatically. Keep the generated build command and output directory, leave the root directory at ./ for a root-level application, and confirm the project uses Node.js 24. No vercel.json is needed.
Vercel creates Preview deployments for pull requests. If merging should wait for that deployment, import the optional ruleset described in GitHub repository protection after the first preview succeeds. Confirm the deployment environment name in GitHub first; multi-project and custom-environment setups may use a different name.
Set the preset on the Nitro plugin in vite.config.ts:
- nitro(),
+ nitro({ preset: "cloudflare-module" }),pnpm build prerenders through Wrangler and writes .output/server/wrangler.json with nodejs_compat and the static-asset binding already configured, so no Cloudflare config is tracked here. Deploy the build output:
cd .output/server && npx wrangler deployCloudflare is also a TanStack Start official partner with a dedicated path that replaces Nitro with @cloudflare/vite-plugin and a tracked wrangler.jsonc. That is a different build layer rather than an addition to this one, so the template stays on Nitro and keeps one build path for every host.
Cloudflare does not provide a template-wide deployment check name. Keep the baseline ruleset and add a required deployment only after the selected Cloudflare integration emits a stable GitHub deployment environment.
Before publishing this repository as a GitHub template, complete the template publishing checklist.
The starter does not choose authentication, persistence, analytics, state management beyond React and TanStack Router, or an environment-schema library. Add each only when the product requires it.
Original template code is available under the MIT License. Vendored source remains under the upstream licenses recorded in THIRD_PARTY_NOTICES.md.