bun tanstack start

Run TanStack Start (full-stack React framework) with Bun.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "bun tanstack start" with this command: npx skills add secondsky/claude-skills/secondsky-claude-skills-bun-tanstack-start

Bun TanStack Start

Run TanStack Start (full-stack React framework) with Bun.

Quick Start

Create new TanStack Start project

bunx create-tanstack-start@latest my-app cd my-app

Install dependencies

bun install

Development

bun run dev

Build

bun run build

Preview

bun run start

Project Setup

package.json

{ "scripts": { "dev": "vinxi dev", "build": "vinxi build", "start": "vinxi start" }, "dependencies": { "@tanstack/react-router": "^1.139.0", "@tanstack/start": "^1.120.0", "react": "^19.2.0", "react-dom": "^19.2.0", "vinxi": "^0.5.10" } }

app.config.ts

import { defineConfig } from "@tanstack/start/config";

export default defineConfig({ server: { preset: "bun", }, });

File-Based Routing

app/ ├── routes/ │ ├── __root.tsx # Root layout │ ├── index.tsx # / │ ├── about.tsx # /about │ ├── users/ │ │ ├── index.tsx # /users │ │ └── $userId.tsx # /users/:userId │ └── api/ │ └── users.ts # /api/users └── client.tsx

Route Components

Basic Route

// app/routes/index.tsx import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/")({ component: Home, });

function Home() { return <h1>Welcome Home</h1>; }

Route with Loader

// app/routes/users/index.tsx import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/users/")({ loader: async () => { const response = await fetch("/api/users"); return response.json(); }, component: Users, });

function Users() { const users = Route.useLoaderData();

return ( <ul> {users.map((user) => ( <li key={user.id}>{user.name}</li> ))} </ul> ); }

Dynamic Routes

// app/routes/users/$userId.tsx import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/users/$userId")({ loader: async ({ params }) => { const response = await fetch(/api/users/${params.userId}); return response.json(); }, component: UserDetail, });

function UserDetail() { const user = Route.useLoaderData(); const { userId } = Route.useParams();

return ( <div> <h1>{user.name}</h1> <p>User ID: {userId}</p> </div> ); }

Server Functions

Define Server Function

// app/routes/users/index.tsx import { createFileRoute } from "@tanstack/react-router"; import { createServerFn } from "@tanstack/start"; import { Database } from "bun:sqlite";

const getUsers = createServerFn("GET", async () => { const db = new Database("data.sqlite"); const users = db.query("SELECT * FROM users").all(); db.close(); return users; });

const createUser = createServerFn("POST", async (name: string) => { const db = new Database("data.sqlite"); db.run("INSERT INTO users (name) VALUES (?)", [name]); db.close(); return { success: true }; });

export const Route = createFileRoute("/users/")({ loader: () => getUsers(), component: Users, });

function Users() { const users = Route.useLoaderData();

const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); const formData = new FormData(e.currentTarget); const name = formData.get("name") as string; await createUser(name); // Refetch or update state };

return ( <div> <form onSubmit={handleSubmit}> <input name="name" placeholder="Name" /> <button type="submit">Add User</button> </form> <ul> {users.map((user) => ( <li key={user.id}>{user.name}</li> ))} </ul> </div> ); }

Server Function with Context

import { createServerFn } from "@tanstack/start"; import { getWebRequest } from "@tanstack/start/server";

const getSession = createServerFn("GET", async () => { const request = getWebRequest(); const cookies = request.headers.get("Cookie"); // Parse and validate session return { userId: "123", role: "admin" }; });

const protectedAction = createServerFn("POST", async (data: any) => { const session = await getSession();

if (session.role !== "admin") { throw new Error("Unauthorized"); }

// Perform action return { success: true }; });

API Routes

// app/routes/api/users.ts import { createAPIFileRoute } from "@tanstack/start/api"; import { Database } from "bun:sqlite";

export const Route = createAPIFileRoute("/api/users")({ GET: async ({ request }) => { const db = new Database("data.sqlite"); const users = db.query("SELECT * FROM users").all(); db.close();

return Response.json(users);

},

POST: async ({ request }) => { const { name } = await request.json();

const db = new Database("data.sqlite");
db.run("INSERT INTO users (name) VALUES (?)", [name]);
db.close();

return Response.json({ success: true });

}, });

Root Layout

// app/routes/__root.tsx import { createRootRoute, Link, Outlet } from "@tanstack/react-router";

export const Route = createRootRoute({ component: Root, });

function Root() { return ( <html> <head> <meta charSet="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>My App</title> </head> <body> <nav> <Link to="/">Home</Link> <Link to="/users">Users</Link> <Link to="/about">About</Link> </nav> <main> <Outlet /> </main> </body> </html> ); }

Error Handling

// app/routes/users/$userId.tsx export const Route = createFileRoute("/users/$userId")({ loader: async ({ params }) => { const response = await fetch(/api/users/${params.userId}); if (!response.ok) { throw new Error("User not found"); } return response.json(); }, errorComponent: ({ error }) => ( <div> <h1>Error</h1> <p>{error.message}</p> </div> ), pendingComponent: () => <div>Loading...</div>, component: UserDetail, });

Search Params

// app/routes/users/index.tsx import { createFileRoute } from "@tanstack/react-router"; import { z } from "zod";

const searchSchema = z.object({ page: z.number().default(1), limit: z.number().default(10), search: z.string().optional(), });

export const Route = createFileRoute("/users/")({ validateSearch: searchSchema, loader: async ({ search }) => { const { page, limit, search: query } = search; // Fetch with pagination return fetchUsers({ page, limit, query }); }, component: Users, });

Deployment

Build for Bun

NITRO_PRESET=bun bun run build bun .output/server/index.mjs

Docker

FROM oven/bun:1 AS builder

WORKDIR /app COPY package.json bun.lockb ./ RUN bun install --frozen-lockfile

COPY . . RUN bun run build

FROM oven/bun:1

WORKDIR /app COPY --from=builder /app/.output ./output

EXPOSE 3000

CMD ["bun", ".output/server/index.mjs"]

Common Errors

Error Cause Fix

Cannot find bun:sqlite

Wrong preset Set server.preset: "bun"

Server function failed

Network error Check function definition

Route not found

File naming Check route file location

Hydration mismatch

Server/client diff Check loader data

When to Load References

Load references/router-api.md when:

  • Advanced routing patterns

  • Route guards

  • Nested layouts

Load references/forms.md when:

  • Form handling

  • Mutations

  • Optimistic updates

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

tailwind-v4-shadcn

No summary provided by upstream source.

Repository SourceNeeds Review
General

aceternity-ui

No summary provided by upstream source.

Repository SourceNeeds Review
General

playwright

No summary provided by upstream source.

Repository SourceNeeds Review
General

zod

No summary provided by upstream source.

Repository SourceNeeds Review