> ## Documentation Index
> Fetch the complete documentation index at: https://better-router.bansal.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Add the Vite plugin, create a page and an API route, and run it locally.

This gets a page, a loader, and an API route running.

## 1. Install

```bash theme={null}
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install better-router@alpha hono
```

Or add the same packages to an existing Vite app: `better-router@alpha`, `hono`, `react`, `react-dom`, and `vite`.

## 2. Enable the plugin

Replace the default Vite plugin list with `betterRouter()`. It already includes `@vitejs/plugin-react`.

```ts title="vite.config.ts" theme={null}
import { defineConfig } from "vite";
import { betterRouter } from "better-router/plugin";

export default defineConfig({
  plugins: [betterRouter()],
});
```

```json title="package.json" theme={null}
{
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build"
  }
}
```

```ts title="src/vite-env.d.ts" theme={null}
/// <reference types="vite/client" />
/// <reference types="better-router/client" />
```

```json title="tsconfig.json" theme={null}
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "bundler",
    "jsx": "react-jsx",
    "strict": true,
    "noEmit": true,
    "types": ["vite/client"]
  },
  "include": ["src", ".better-router", "vite.config.ts"]
}
```

Delete Vite's `index.html` and `src/main.tsx`. Pages live in `src/routes`, not a client entry.

Full compiler options are in [TypeScript](/typescript).

## 3. Layout and page

Layouts wrap the page tree. They do **not** render `<html>` or `<body>` — that is `_document.tsx`, or the default document the plugin already provides.

```tsx title="src/routes/_layout.tsx" theme={null}
import type { ReactNode } from "react";
import { Link } from "better-router/react";

export default function Layout({ children }: { children: ReactNode }) {
  return (
    <div>
      <nav>
        <Link href="/">Home</Link>
      </nav>
      {children}
    </div>
  );
}
```

```tsx title="src/routes/index.tsx" theme={null}
type HomeProps = { message: string };

export default function Home({ message }: HomeProps) {
  return <h1>{message}</h1>;
}
```

```ts title="src/routes/index.server.tsx" theme={null}
export function loader() {
  return { message: "Hello from better-router" };
}
```

Loader data is passed as page props **and** available from `useLoaderData()`. Use whichever you prefer. The `.server.tsx` file never ships to the browser.

## 4. API route

```ts title="src/routes/api/hello.ts" theme={null}
import { defineHandler } from "better-router";

export const GET = defineHandler(() => {
  return { ok: true };
});
```

Objects become JSON. See [Routing](/routing) for redirects, status codes, and validation.

## 5. Run it

```bash theme={null}
npm run dev
```

* App: `http://localhost:5173`
* API: `http://localhost:5173/api/hello`

The first page request is SSR HTML. Clicks on `<Link>` fetch JSON and swap the page on the client.

<Note>
  `vite build` emits `dist/client` (assets) and `dist/server` (the Worker module). To deploy that to Cloudflare, see [Cloudflare Workers](/cloudflare).
</Note>

## What you add next

| Goal                            | Page                                    |
| ------------------------------- | --------------------------------------- |
| Nested routes, params, groups   | [Routing](/routing)                     |
| Shared chrome and HTML document | [Layouts](/layouts)                     |
| Forms and mutations             | [Loaders and actions](/loaders-actions) |
| Cloudflare deploy               | [Cloudflare Workers](/cloudflare)       |
| Bindings on `env`               | [Bindings](/bindings)                   |
| Cron, queues, inbound email     | [Worker entrypoint](/worker)            |
