# Create Courier

Set Courier up in one command, in your project or a new one: the typed API, the route the browser calls it through, Studio and mock data.

`@noverax/create-courier` sets Courier up in one command. It finds your framework, shows what it is about to do, and once you agree writes the files, installs the packages with your package manager and type-checks what it added. You get a working page at `/courier` before you have a backend: the example API answers from a mock that Studio runs.

## In your project

Run it in the project's folder:

**npm**

```bash
npx @noverax/create-courier
```

**pnpm**

```bash
pnpm create @noverax/courier
```

**yarn**

```bash
yarn create @noverax/courier
```

**bun**

```bash
bun create @noverax/courier
```

It prints the plan and asks before it changes anything:

```text
Set Courier up in shop (Next.js 16.4.0, npm)

Files
  + src/courier/api.ts             your API, typed, with an example to start from
  + courier.routes.ts              the endpoints a page may call, written again by Studio as you mark them
  + courier.config.ts              lists your APIs for the app, Studio and agents
  + courier.mocks.ts               the mock Studio runs on port 7001
  + src/app/api/request/route.ts   the route the browser calls your API through
  + src/courier/query.ts           React Query hooks for your API
  + src/app/courier/page.tsx       a page that shows Courier at work
  + src/instrumentation.ts         registers your APIs as the server starts
  + src/instrumentation-client.ts  the browser's connection to Studio

Changes to your files
  ~ package.json                   adds Courier's scripts
      +     "studio": "courier-studio"

Packages
  + @noverax/courier @noverax/courier-next @noverax/courier-react @tanstack/react-query zod @noverax/courier-studio-core
  + @noverax/courier-studio @noverax/courier-mock hono @hono/node-server  (dev)
```

Then start Studio, which runs the mock, and your app:

```bash
npm run studio
npm run dev
```

Open `/courier`: the users the mock answers with, and a form that creates one, each call in Studio's timeline.

## In a new project

Point it at a folder that does not exist yet, and name the framework:

```bash
npx @noverax/create-courier shop --framework next
```

It creates the project with the framework's own generator — `create-next-app`, `sv`, `create-astro` and the others, run without a question at the major the setup is checked against — puts right what a template gets wrong for the project it makes, installs its packages with your package manager, and sets Courier up in it. Express has no generator of its own: the command writes a minimal server in TypeScript. In a terminal, it asks for the framework when `--framework` is left out, and whether to offer the API to [AI agents](#ai-agents), all before it makes anything.

A project it creates is moved to TypeScript 6 where its template came with an older one. A project you already have keeps the TypeScript it has, and the plan says how to move when you are ready: the command to run, and what TypeScript 6 deprecates that your `tsconfig.json` sets — `moduleResolution: "node"`, `baseUrl`, `downlevelIteration` — with what to write instead. Courier's entries resolve under `"moduleResolution": "node"` meanwhile; see [an existing project](/docs/installation#an-existing-project).

## What it sets up

| Framework | Where your API is served | What it changes in your files |
|---|---|---|
| Next.js | `app/api/request/route.ts`, registered from `instrumentation.ts` | `next.config` only when Studio's default port is taken |
| Nuxt | `server/api/request.ts`, registered from a Nitro plugin | Studio's module in `nuxt.config`; `app.vue` renders pages where it showed the welcome |
| SvelteKit | `src/routes/api/request/+server.ts`, registered from `hooks.server.ts` | Studio's plugin in `vite.config` |
| Astro | `src/pages/api/request.ts`, on demand, registered from the middleware | Studio's integration in `astro.config` |
| React Router, Remix | `app/routes/api.request.ts` | the routes in `app/routes.ts`; Studio's plugin in `vite.config` |
| SolidStart | `src/routes/api/request.ts` | Studio's plugin in `vite.config` |
| React with Vite | no server: the browser calls your API directly | Studio's plugin in `vite.config` |
| Vue with Vite | no server: the browser calls your API directly | Studio's plugin in `vite.config` |
| Expo | no server: the app calls your API directly | a Courier tab in the template's tabs |
| Express | a router on `/api/request` and `/courier` | the router mounted after `express()` |
| Hono | routes on `/api/request` and `/courier` | the routes mounted after `new Hono()`; `include` in a `tsconfig` that compiles `src/` |
| Fastify | a plugin on `/api/request` and `/courier` | `.courier/` kept out of `fastify start -w` |
| NestJS | a module on `/api/request` and `/courier` | the module imported into your root module |

Every setup in a project without Courier adds `courier.config.ts`, the list of your APIs that your server, Studio and the [MCP server](/docs/agents/overview) read; `courier.mocks.ts`, the mock Studio starts with itself; and your API's definition, with its Zod schemas and the `.expose()` marks that open its endpoints to a page. Where a page calls the API through your server, it adds `courier.routes.ts` too: the [routes](/docs/proxy-mode/expose) the page's client takes, as Courier writes them from the marks, so the project compiles before Studio first runs — and `@noverax/courier-cli` with a `routes` script, which writes them again without Studio and, with `--check`, fails a CI job when they are out of date. A server compiled by `tsc` from `src/` — Express, Hono, Fastify, NestJS — cannot import a file at the project's root, so its list lives in `src/courier/config.ts`, which the server registers from, and `courier.config.ts` passes it on to Studio and agents. It is still one list: an API Studio imports is declared where the list is written.

## What it will not do

- **Change anything you have not seen.** The plan comes first; without a terminal to answer, in CI or for an agent, nothing changes unless `--yes` is passed. `--dry-run` shows the plan and stops, and Ctrl+C at any of its questions stops it with nothing changed.
- **Replace a file of yours.** A file is only ever added. Where a file of yours stands where Courier's would go — your own `instrumentation.ts`, say — it is kept, and the lines it lacks are listed for you.
- **Offer what you have.** In a project whose `courier.config.ts` declares APIs already, it adds no example — no API, page, mock or query hooks — and says how many APIs the config declares. It reads your code for what is wired up: the config's APIs registered, the server and the browser connected to Studio, the proxy route, Studio's plugin in your bundler's config. Only a real call counts, not one in a comment or a string, and only in a file the app loads — by the framework's own convention, as its entry, or imported by another file, through a relative path or one of your aliases (tsconfig `paths` and `baseUrl`, package.json `imports`): a router nothing mounts still has its step. A change it makes never imports a name your file binds already, nor adds a route whose URL path a route of yours has: those are left to you. A file that lacks a part is shown only that part. The config is found under any of the names Studio reads, `courier.config.mjs` among them, and no `courier.config.ts` is added beside it. A package you list as a dependency or a dev one is not installed again, nor a peer or optional one that Node finds installed, in your project or hoisted in a workspace; one listed there alone and not installed is added, and the plan says why. One of Courier's on another release line is named and left as it is. Scripts are added to `package.json` in its own layout: `studio` where Studio is set up, and — where pages call through your server and the project marks an endpoint with `.expose()` or has a routes module — `routes`, with `@noverax/courier-cli` to run it. A script of yours under one of those names is kept as it is, and the step that would run Courier's runs its command instead.
- **Edit a file it cannot read.** A change to a file of yours is made only where the file has a shape the command knows: one default export of a config object, one `const app = express()`. It is shown line by line in the plan and checked against the file right before it is written; a file that changed meanwhile stops the setup with its name. Anywhere else, the change is left to you, with the lines to add.
- **Take a port that is taken.** Studio takes 6280 and the mock 7001 unless something listens there already, another project's Studio say; then the next free one, written in `courier.config.ts` and `courier.mocks.ts`.

## Your own API

```bash
npx @noverax/create-courier --openapi https://petstore3.swagger.io/api/v3/openapi.json
```

Imports an OpenAPI, Swagger or Postman specification in place of the example, with Studio's own importer: the typed code is written and the API is declared in `courier.config.ts`. See [Import an API](/docs/studio/import-api).

Behind a corporate proxy, npm installs through the proxy its own settings or `HTTPS_PROXY` name, and the specification is fetched through it once `NODE_USE_ENV_PROXY=1` is set — see [Proxies & Certificates](/docs/advanced/proxies-and-certificates#create-courier).

## AI agents

```bash
npx @noverax/create-courier --mcp
```

Writes `agents: { offer: "reads" }` into the config — every read is offered to agents, a write once you mark it `.agent()` — describes the example's reads with `.agent()`, and adds `.mcp.json`, which Claude Code reads, so your editor's agent can call your API through the same middleware as your app. An imported API's reads are offered the same way, each described by its specification's summary. In a project set up before, it adds the policy to the config you have, unless the config says already what agents may call. In a terminal, it asks, for a project you have and for one it creates; with `--yes`, or without a terminal, it leaves agents out unless `--mcp` is passed. See [What agents may call](/docs/agents/overview#what-agents-may-call).

## Options

| Option | |
|---|---|
| `[dir]` | The project's folder, or a new one to create (default: the working directory) |
| `--framework <name>` | `next`, `nuxt`, `sveltekit`, `astro`, `react-router`, `remix`, `solid-start`, `expo`, `nestjs`, `fastify`, `hono`, `express`, `react`, `vue` (default: found in `package.json`) |
| `--openapi <spec>` | Import your API from a specification, a URL or a file, in place of the example |
| `--name <name>` | The imported API's name (default: from the specification) |
| `--no-studio` | Leave Studio out |
| `--no-mocks` | Leave the example's mock out |
| `--mcp` | Offer the API's reads to AI agents in your editor |
| `--package-manager <name>` | `npm`, `pnpm`, `yarn` or `bun` (default: the project's, or the one that started the command) |
| `--no-install` | Write the files, and name the install commands |
| `--yes`, `-y` | Go ahead without asking |
| `--dry-run` | Show the plan, and change nothing |

It needs Node.js 22 or later, and a project with a `tsconfig.json`: Courier is typed end to end.
