Skip to content

Getting StartedCreate Courier

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.

8 min readUpdated both modes

@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:

npx @noverax/create-courier

It prints the plan and asks before it changes anything:

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, 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.

What it sets up

FrameworkWhere your API is servedWhat it changes in your files
Next.jsapp/api/request/route.ts, registered from instrumentation.tsnext.config only when Studio's default port is taken
Nuxtserver/api/request.ts, registered from a Nitro pluginStudio's module in nuxt.config; app.vue renders pages where it showed the welcome
SvelteKitsrc/routes/api/request/+server.ts, registered from hooks.server.tsStudio's plugin in vite.config
Astrosrc/pages/api/request.ts, on demand, registered from the middlewareStudio's integration in astro.config
React Router, Remixapp/routes/api.request.tsthe routes in app/routes.ts; Studio's plugin in vite.config
SolidStartsrc/routes/api/request.tsStudio's plugin in vite.config
React with Viteno server: the browser calls your API directlyStudio's plugin in vite.config
Vue with Viteno server: the browser calls your API directlyStudio's plugin in vite.config
Expono server: the app calls your API directlya Courier tab in the template's tabs
Expressa router on /api/request and /courierthe router mounted after express()
Honoroutes on /api/request and /courierthe routes mounted after new Hono(); include in a tsconfig that compiles src/
Fastifya plugin on /api/request and /courier.courier/ kept out of fastify start -w
NestJSa module on /api/request and /courierthe 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 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 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.

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.

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.

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-studioLeave Studio out
--no-mocksLeave the example's mock out
--mcpOffer 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-installWrite the files, and name the install commands
--yes, -yGo ahead without asking
--dry-runShow 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.