# Quick start

> A running app in one command, or added to a project you already have.

## A new app

```sh
bun create rsc-kit@latest my-app
cd my-app
bun run dev
```

That is it. You get a page, a layout, a client component and a Vite config,
wired together and running. There is no server file — Nitro builds one from the
preset in that config when you build.

It asks a few questions, each with a flag for a script: where it runs, the
React Compiler, Tailwind, oxlint, and which **validation library** you want —
Zod, Valibot or ArkType. That one is asked once because everything schema-shaped
hangs off it: a form's schema, `action.input()`, a page's `searchParams`, and
**typed environment variables**, which it offers next. Say yes and you get
`src/env.ts`:

```ts title="src/env.ts"
export const env = createEnv({
  server: {
    NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
    // DATABASE_URL: z.url(),
  },
  clientPrefix: 'VITE_',
  client: {},
  // No bare process.env: import.meta.env carries the VITE_ values, and
  // the file does not throw in the browser if a client component imports it.
  runtimeEnv: { ...(typeof process === 'undefined' ? {} : process.env), ...import.meta.env },
  emptyStringAsUndefined: true,
})
```

A missing or malformed variable is refused at startup with its name, not as an
`undefined` three calls later; `env.DATABASE_URL` is typed everywhere it is
read; and a server variable can never reach the browser — a browser-readable
one has to start with `VITE_`. That is [`@t3-oss/env-core`](https://env.t3.gg),
with the schema in whichever library you chose. `.env.example` is written
beside it and is the one that gets committed.

Import `env` from server code. A client component reads its `VITE_` value
from `import.meta.env.VITE_…` directly: importing `src/env.ts` there brings
the validator along to read one string, about 20 kB gzipped for Zod. The
value is still checked, because the server imports `env` when it starts.

```sh
bun create rsc-kit@latest my-app --validation=valibot --env   # scripted
```

When you are ready to ship:

```sh
bun run build
bun run start
```

The build prints what it did:

```
  ○  /

  ○  (Static)  prerendered as static content

  1 static
```

Pages marked `○` are **static**: rendered once at build time rather than for
each visitor.

## An app you already have

Already have a project? Add rsc-kit to it:

```sh
bunx rsc-kit@latest init
```

It reads your `package.json`, works out which server you use and where your
source lives, and writes only what is missing. A project with no
`package.json` — a Go or Rust service getting its frontend — is given its
first one. And in an empty directory, or a fresh clone of an empty repository,
there is nothing to add to, so `init` starts a new app right there, leaving the
README alone and adding what the app needs ignored to the `.gitignore`:

```
  server      hono
  source      src
  react       will be added

  + src/app/layout.tsx
  + src/app/page.tsx
  + vite.config.ts
  ~ package.json  — added @rsc-kit/core, react, react-dom, vite, nitro, …
  ~ scripts  — dev, build, start, compile, typecheck
```

No server file. Nitro builds one around the route tree, so the app owns a route
tree and a vite config and nothing in between.

**It never overwrites anything.** If you already have a `vite.config.ts`, it
prints the edit to make instead of replacing work you have done. Running it twice is safe — the second run just tells you what is already
in place.

Then:

```sh
bun install
bun run dev
```

## Add a page

Routes are directories under `src/app`. Create a folder, put a `page.tsx` in
it, and it exists:

```tsx title="src/app/about/page.tsx"
export default function AboutPage() {
  return <h1>About</h1>
}
```

```sh
bun run build   # the route tree is read at build time
```

## Doing it by hand

If you would rather wire it up yourself — or the CLI cannot reach your
setup — [Installation](/installation) walks through the same result one file at
a time.

## Where next

- [Routing](/guides/routing) — layouts, dynamic segments, parallel slots
- [Server actions](/guides/server-actions) — mutations without an API route
- [Where it runs](/hosts/where-it-runs) — presets, and compiling to a binary
