Skip to content

Latest commit

 

History

History
347 lines (255 loc) · 11.2 KB

File metadata and controls

347 lines (255 loc) · 11.2 KB

Getting Started And Configuration

This guide expands on the quick start in the root README and covers the day-to-day setup flow for next-openapi-gen across the currently supported frameworks.

Requirements

  • Node.js >=24
  • One of the supported frameworks:
    • Next.js with App Router or Pages Router
    • TanStack Router
    • React Router
  • Route handlers documented with JSDoc tags when you want explicit metadata

Install

Choose your package manager:

pnpm add -D next-openapi-gen
npm install --save-dev next-openapi-gen
yarn add --dev next-openapi-gen

Pick your framework

init can scaffold framework-aware defaults for all supported stacks.

Framework init flag Default apiDir Default docs page output Default includeOpenApiRoutes
Next.js --framework next ./src/app/api src/app/<docsUrl>/page.tsx when src/ exists false
TanStack Router --framework tanstack ./src/routes/api src/routes/<docsUrl>.tsx true
React Router --framework react-router ./src/routes/api src/routes/<docsUrl>.tsx or src/routes/_index.tsx true

Next.js is the default, so pnpm exec openapi-gen init and pnpm exec openapi-gen init --framework next are equivalent.

First run

Initialize the project:

# Next.js (default)
pnpm exec openapi-gen init

# TanStack Router
pnpm exec openapi-gen init --framework tanstack

# React Router
pnpm exec openapi-gen init --framework react-router

This creates:

  • a config file in the project root
  • an API docs page at /api-docs by default unless you pass --ui none
  • a UI integration, with Scalar as the default

Then generate the spec:

pnpm exec openapi-gen generate

By default this writes public/openapi.json.

Recommended workflow

Use init once, then rerun generate whenever your routes or schemas change.

A typical setup is:

  1. Add or update route JSDoc metadata.
  2. Update your Zod schemas, TypeScript types, or reusable OpenAPI fragments.
  3. Run pnpm exec openapi-gen generate.
  4. Review the generated spec or open /api-docs.

For local development, --watch is usually the best default:

pnpm exec openapi-gen generate --watch

If you want reusable scripts:

{
  "scripts": {
    "openapi:generate": "openapi-gen generate",
    "openapi:watch": "openapi-gen generate --watch"
  }
}

Configuration file names

init still writes next.openapi.json by default for backward compatibility. During the CLI rename transition, config discovery also accepts:

  • openapi-gen.config.ts
  • openapi-gen.config.js
  • openapi-gen.config.json
  • legacy next-openapi.config.*
  • legacy next.openapi.json

The modern openapi-gen.config.* names are the forward-looking option. Legacy names still load, but they emit deprecation warnings.

If you prefer typed configuration, use defineConfig:

import { defineConfig } from "next-openapi-gen";

export default defineConfig({
  openapi: "3.0.0",
  apiDir: "./src/app/api",
  schemaDir: "./src",
  schemaType: "typescript",
});

Choosing an OpenAPI version

  • Use 3.0.0 when you want the most conservative output for downstream tools.
  • Use 3.1.0 when you want JSON Schema 2020-12-aligned features such as jsonSchemaDialect.
  • Use 3.2.0 when you want richer route metadata such as querystring, enhanced tags, sequential media, and richer example objects.

The checked-in examples follow that split on purpose: most apps stay on 3.0, ../apps/next-app-next-config demonstrates a typed 3.1 config, and ../apps/next-app-zod showcases 3.2 route and document features.

Configuration shape

init creates a config file like this:

{
  "openapi": "3.0.0",
  "info": {
    "title": "Next.js API",
    "version": "1.0.0",
    "description": "API generated by next-openapi-gen"
  },
  "apiDir": "./src/app/api",
  "routerType": "app",
  "schemaDir": "./src",
  "schemaType": "zod",
  "schemaFiles": [],
  "outputFile": "openapi.json",
  "outputDir": "./public",
  "docsUrl": "api-docs",
  "includeOpenApiRoutes": false,
  "ignoreRoutes": [],
  "debug": false
}

Framework-specific defaults mainly change apiDir, framework.kind, and includeOpenApiRoutes.

Important options

Option Purpose
openapi Target OpenAPI version: "3.0.0", "3.1.0", or "3.2.0"
apiDir Route directory to scan
routerType "app" for App Router or "pages" for Pages Router
schemaDir One directory or an array of directories to search for types and schemas
schemaType "zod", "typescript", or both
schemaFiles YAML or JSON OpenAPI fragments merged into the final document
outputDir / outputFile Where the generated spec is written
docsUrl Route path for the generated docs UI
includeOpenApiRoutes When true, only handlers tagged with @openapi are included
ignoreRoutes Wildcard patterns for routes you never want in the output
defaultResponseSet / responseSets Shared error-response bundles
errorConfig Templates for consistent generated error schemas
debug Extra generation logs for diagnosing route or schema discovery

Choosing a schema strategy

Zod-first

Use this when your API contracts already live in exported Zod schemas:

{
  "schemaType": "zod",
  "schemaDir": "./src/schemas"
}

TypeScript-first

Use this when your project primarily documents route contracts with exported TypeScript types:

{
  "schemaType": "typescript",
  "schemaDir": "./src/types"
}

Mixed schemas for migrations

Use this when you are gradually moving from TypeScript to Zod or combining code schemas with external fragments:

{
  "schemaType": ["zod", "typescript"],
  "schemaDir": "./src/schemas",
  "schemaFiles": ["./schemas/external-api.yaml"]
}

Resolution priority is:

  1. schemaFiles
  2. zod
  3. typescript

See workflows and integrations for more mixed-schema examples.

Choose the right integration

All frameworks can use the CLI directly. Add a framework-specific integration when you want generation tied to the dev server or build pipeline.

Integration Use when Notes
CLI only You want explicit generate or generate --watch scripts Works across all frameworks and keeps behavior easy to reason about
next-openapi-gen/next You want a Next-specific adapter surface createNextOpenApiAdapter() generates on build completion
next-openapi-gen/vite You are using TanStack Router on Vite, or want the shared Vite path Generates on build start and watches in dev unless watch: false
next-openapi-gen/react-router You want a React Router-specific plugin entrypoint Mirrors the React Router framework adapters explicitly

Next.js

Use the CLI directly for the simplest setup, or wire in the adapter entrypoint when you want generation attached to the Next build lifecycle.

createNextOpenApiAdapter() is the behavior-bearing integration:

import { createNextOpenApiAdapter } from "next-openapi-gen/next";

export default createNextOpenApiAdapter();

withNextOpenApi() wires the Next build to an internal next-openapi-gen adapter automatically. Use it when you want to stay in next.config.* without checking in a separate adapter module.

TanStack Router

The public Vite entrypoint is the normal integration path:

import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import react from "@vitejs/plugin-react";
import { createViteOpenApiPlugin } from "next-openapi-gen/vite";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [tanstackStart(), createViteOpenApiPlugin(), react()],
});

React Router

React Router projects can use the React Router-specific subpath export or the shared Vite integration when the app already runs on Vite.

Pages Router setup

next-openapi-gen supports the legacy Pages Router.

To use it:

  1. Set routerType to "pages".
  2. Point apiDir at your Pages Router API directory, usually pages/api.
  3. Add @method to handlers so the generator can map exported functions to HTTP methods.

See ../apps/next-pages-router for a runnable example.

Response sets and shared errors

If your API repeats the same error responses on most routes, define response sets once in your config:

{
  "defaultResponseSet": "common",
  "responseSets": {
    "common": ["400", "401", "500"],
    "public": ["400", "500"],
    "auth": ["400", "401", "403", "500"]
  }
}

You can then override the default set per route with @responseSet or add individual extra responses with @add.

Ignoring routes

There are two common ways to keep internal or incomplete endpoints out of the spec:

  • add @ignore to a specific handler
  • add wildcard patterns to ignoreRoutes

Example:

{
  "ignoreRoutes": ["/internal/*", "/debug", "/admin/test/*"]
}

Production notes

  • By default the spec is written to public/openapi.json, which makes it easy to serve and inspect. If you do not want that file publicly accessible, point outputDir somewhere else and wire the UI or deployment flow accordingly.
  • The generated docs page is a normal application route. Treat it like any other public route if your API docs should be private.
  • If you only want the OpenAPI file and not the UI page, run init with --ui none.

Where to go next