next-openapi-gen 0.10.5 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +407 -1047
  2. package/dist/cli.d.ts +4 -0
  3. package/dist/cli.js +8599 -0
  4. package/dist/index.d.ts +18 -0
  5. package/dist/index.js +8645 -26
  6. package/dist/next/index.d.ts +1 -0
  7. package/dist/next/index.js +7965 -0
  8. package/dist/react-router/index.d.ts +1 -0
  9. package/dist/react-router/index.js +7134 -0
  10. package/dist/vite/index.d.ts +1 -0
  11. package/dist/vite/index.js +7134 -0
  12. package/package.json +103 -79
  13. package/{dist/components/rapidoc.js → templates/init/ui/nextjs/rapidoc.tsx} +16 -20
  14. package/templates/init/ui/nextjs/redoc.tsx +11 -0
  15. package/{dist/components/scalar.js → templates/init/ui/nextjs/scalar.tsx} +15 -21
  16. package/{dist/components/stoplight.js → templates/init/ui/nextjs/stoplight.tsx} +11 -17
  17. package/templates/init/ui/nextjs/swagger.tsx +17 -0
  18. package/templates/init/ui/reactrouter/rapidoc.tsx +15 -0
  19. package/templates/init/ui/reactrouter/redoc.tsx +9 -0
  20. package/templates/init/ui/reactrouter/scalar.tsx +14 -0
  21. package/templates/init/ui/reactrouter/stoplight.tsx +10 -0
  22. package/templates/init/ui/reactrouter/swagger.tsx +11 -0
  23. package/templates/init/ui/tanstack/rapidoc.tsx +21 -0
  24. package/templates/init/ui/tanstack/redoc.tsx +14 -0
  25. package/templates/init/ui/tanstack/scalar.tsx +19 -0
  26. package/templates/init/ui/tanstack/stoplight.tsx +15 -0
  27. package/templates/init/ui/tanstack/swagger.tsx +16 -0
  28. package/templates/init/ui/template-types.d.ts +9 -0
  29. package/dist/commands/generate.js +0 -24
  30. package/dist/commands/init.js +0 -194
  31. package/dist/components/redoc.js +0 -17
  32. package/dist/components/swagger.js +0 -21
  33. package/dist/lib/app-router-strategy.js +0 -66
  34. package/dist/lib/drizzle-zod-processor.js +0 -329
  35. package/dist/lib/logger.js +0 -39
  36. package/dist/lib/openapi-generator.js +0 -171
  37. package/dist/lib/pages-router-strategy.js +0 -198
  38. package/dist/lib/route-processor.js +0 -349
  39. package/dist/lib/router-strategy.js +0 -1
  40. package/dist/lib/schema-processor.js +0 -1612
  41. package/dist/lib/utils.js +0 -283
  42. package/dist/lib/zod-converter.js +0 -2133
  43. package/dist/openapi-template.js +0 -99
  44. package/dist/types.js +0 -1
package/README.md CHANGED
@@ -1,1047 +1,407 @@
1
- # next-openapi-gen
2
-
3
- Automatically generate OpenAPI 3.0 documentation from Next.js projects, with support for Zod schemas and TypeScript types.
4
-
5
- ## Features
6
-
7
- - ✅ Automatic OpenAPI 3.0 documentation generation from Next.js App Router and Pages Router 🆕
8
- - ✅ Multiple schema types: `TypeScript`, `Zod`, `Drizzle-Zod`, or `custom YAML/JSON` files
9
- - Mix schema sources simultaneously - perfect for gradual migrations
10
- - ✅ JSDoc comments with intelligent parameter examples
11
- - Multiple UI interfaces: `Scalar`, `Swagger`, `Redoc`, `Stoplight`, and `RapiDoc` available at `/api-docs` url
12
- - ✅ Auto-detection of path parameters (e.g., `/users/[id]/route.ts`)
13
- - Intuitive CLI for quick setup and generation
14
-
15
- ## Supported interfaces
16
-
17
- - Scalar 💡(default)
18
- - Swagger
19
- - Redoc
20
- - Stoplight Elements
21
- - RapiDoc
22
-
23
- ## Installation
24
-
25
- ```bash
26
- npm install next-openapi-gen --save-dev
27
- ```
28
-
29
- ## Quick Start
30
-
31
- ```bash
32
- # Initialize OpenAPI configuration
33
- npx next-openapi-gen init
34
-
35
- # Generate OpenAPI documentation
36
- npx next-openapi-gen generate
37
- ```
38
-
39
- > [!TIP]
40
- > Scalar UI and Zod are set by default
41
-
42
-
43
- ### Init Command Options
44
-
45
- | Option | Choices | Default | Description |
46
- |--------|---------|---------|-------------|
47
- | `--ui` | `scalar`, `swagger`, `redoc`, `stoplight`, `rapidoc`, `none` | `scalar` | UI framework for API docs |
48
- | `--schema` | `zod`, `typescript` | `zod` | Schema validation tool |
49
- | `--docs-url` | any string | `api-docs` | URL path for documentation page |
50
- | `--output` | any path | `next.openapi.json` | Output file for OpenAPI template |
51
-
52
- > [!TIP]
53
- > Use `--ui none` to skip UI setup and only generate the OpenAPI specification file.
54
-
55
- ## Configuration
56
-
57
- During initialization (`npx next-openapi-gen init`), a configuration file `next.openapi.json` will be created in the project's root directory:
58
-
59
- ```json
60
- {
61
- "openapi": "3.0.0",
62
- "info": {
63
- "title": "Next.js API",
64
- "version": "1.0.0",
65
- "description": "API generated by next-openapi-gen"
66
- },
67
- "servers": [
68
- {
69
- "url": "http://localhost:3000",
70
- "description": "Local server"
71
- }
72
- ],
73
- "apiDir": "src/app/api", // or "pages/api" for Pages Router
74
- "routerType": "app", // "app" (default) or "pages" for legacy Pages Router
75
- "schemaDir": "src/types", // or ["src/types", "src/schemas"] for multiple directories
76
- "schemaType": "zod", // or "typescript", or ["zod", "typescript"] for multiple
77
- "schemaFiles": [], // Optional: ["./schemas/models.yaml", "./schemas/api.json"]
78
- "outputFile": "openapi.json",
79
- "outputDir": "./public",
80
- "docsUrl": "/api-docs",
81
- "includeOpenApiRoutes": false,
82
- "ignoreRoutes": [],
83
- "debug": false
84
- }
85
- ```
86
-
87
- ### Configuration Options
88
-
89
- | Option | Description |
90
- | ---------------------- | ----------------------------------------------------------------------------- |
91
- | `apiDir` | Path to the API directory |
92
- | `routerType` | Router type: `"app"` (default) or `"pages"` for legacy Pages Router |
93
- | `schemaDir` | Path to types/schemas directory, or array of paths for multiple directories |
94
- | `schemaType` | Schema type: `"zod"`, `"typescript"`, or `["zod", "typescript"]` for multiple |
95
- | `schemaFiles` | Optional: Array of custom OpenAPI schema files (YAML/JSON) to include |
96
- | `outputFile` | Name of the OpenAPI output file |
97
- | `outputDir` | Directory where OpenAPI file will be generated (default: `"./public"`) |
98
- | `docsUrl` | API documentation URL (for Swagger UI) |
99
- | `includeOpenApiRoutes` | Whether to include only routes with @openapi tag |
100
- | `ignoreRoutes` | Array of route patterns to exclude from documentation (supports wildcards) |
101
- | `defaultResponseSet` | Default error response set for all endpoints |
102
- | `responseSets` | Named sets of error response codes |
103
- | `errorConfig` | Error schema configuration |
104
- | `debug` | Enable detailed logging during generation |
105
-
106
- ## Documenting Your API
107
-
108
- ### With Zod Schemas
109
-
110
- ```typescript
111
- // src/app/api/products/[id]/route.ts
112
-
113
- import { NextRequest, NextResponse } from "next/server";
114
- import { z } from "zod";
115
-
116
- export const ProductParams = z.object({
117
- id: z.string().describe("Product ID"),
118
- });
119
-
120
- export const ProductResponse = z.object({
121
- id: z.string().describe("Product ID"),
122
- name: z.string().describe("Product name"),
123
- price: z.number().positive().describe("Product price"),
124
- });
125
-
126
- /**
127
- * Get product information
128
- * @description Fetches detailed product information by ID
129
- * @pathParams ProductParams
130
- * @response ProductResponse
131
- * @openapi
132
- */
133
- export async function GET(
134
- request: NextRequest,
135
- { params }: { params: { id: string } }
136
- ) {
137
- // Implementation...
138
- }
139
- ```
140
-
141
- ### With TypeScript Types
142
-
143
- ```typescript
144
- // src/app/api/users/[id]/route.ts
145
-
146
- import { NextRequest, NextResponse } from "next/server";
147
-
148
- type UserParams = {
149
- id: string; // User ID
150
- };
151
-
152
- type UserResponse = {
153
- id: string; // User ID
154
- name: string; // Full name
155
- email: string; // Email address
156
- };
157
-
158
- /**
159
- * Get user information
160
- * @description Fetches detailed user information by ID
161
- * @pathParams UserParams
162
- * @response UserResponse
163
- * @openapi
164
- */
165
- export async function GET(
166
- request: NextRequest,
167
- { params }: { params: { id: string } }
168
- ) {
169
- // Implementation...
170
- }
171
- ```
172
-
173
- ### With Drizzle-Zod
174
-
175
- ```typescript
176
- // src/db/schema.ts - Define your Drizzle table
177
- import { pgTable, serial, varchar, text } from "drizzle-orm/pg-core";
178
-
179
- export const posts = pgTable("posts", {
180
- id: serial("id").primaryKey(),
181
- title: varchar("title", { length: 255 }).notNull(),
182
- content: text("content").notNull(),
183
- });
184
-
185
- // src/schemas/post.ts - Generate Zod schema with drizzle-zod
186
- import { createInsertSchema, createSelectSchema } from "drizzle-zod";
187
- import { posts } from "@/db/schema";
188
-
189
- export const CreatePostSchema = createInsertSchema(posts, {
190
- title: (schema) => schema.title.min(5).max(255).describe("Post title"),
191
- content: (schema) => schema.content.min(10).describe("Post content"),
192
- });
193
-
194
- export const PostResponseSchema = createSelectSchema(posts);
195
-
196
- // src/app/api/posts/route.ts - Use in your API route
197
- /**
198
- * Create a new post
199
- * @description Create a new blog post with Drizzle-Zod validation
200
- * @body CreatePostSchema
201
- * @response 201:PostResponseSchema
202
- * @openapi
203
- */
204
- export async function POST(request: NextRequest) {
205
- const body = await request.json();
206
- const validated = CreatePostSchema.parse(body);
207
- // Implementation...
208
- }
209
- ```
210
-
211
- ## JSDoc Documentation Tags
212
-
213
- | Tag | Description |
214
- |------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
215
- | `@description` | Endpoint description |
216
- | `@operationId` | Custom operation ID (overrides auto-generated ID) |
217
- | `@pathParams` | Path parameters type/schema |
218
- | `@params` | Query parameters type/schema (use `@queryParams` if you have prettier-plugin-jsdoc conflicts) |
219
- | `@body` | Request body type/schema |
220
- | `@bodyDescription` | Request body description |
221
- | `@response` | Response type/schema with optional code and description (`User`, `201:User`, `User:Description`, `201:User:Description`) |
222
- | `@responseDescription` | Response description |
223
- | `@responseSet` | Override default response set (`public`, `auth`, `none`) |
224
- | `@add` | Add custom response codes (`409:ConflictResponse`, `429`) |
225
- | `@contentType` | Request body content type (`application/json`, `multipart/form-data`) |
226
- | `@auth` | Authorization type (e.g., `bearer`, `basic`, `apikey`, or a custom type) — supports multiple auths using comma separator (e.g., `bearer, CustomType`) |
227
- | `@tag` | Custom tag |
228
- | `@deprecated` | Marks the route as deprecated |
229
- | `@openapi` | Marks the route for inclusion in documentation (if includeOpenApiRoutes is enabled) |
230
- | `@ignore` | Excludes the route from OpenAPI documentation |
231
- | `@method` | HTTP method for Pages Router (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`) - required for Pages Router only |
232
-
233
- ## Pages Router Support 🆕
234
-
235
- The library now supports the legacy Next.js Pages Router. To use it:
236
-
237
- 1. Set `routerType` to `"pages"` in your configuration
238
- 2. Use the `@method` JSDoc tag to specify HTTP methods
239
-
240
- See **[next15-pages-router](./examples/next15-pages-router)** for a complete working example.
241
-
242
- ## CLI Usage
243
-
244
- ### 1. Initialization
245
-
246
- ```bash
247
- npx next-openapi-gen init
248
- ```
249
-
250
- This command will generate following elements:
251
-
252
- - Generate `next.openapi.json` configuration file
253
- - Set up `Scalar` UI for documentation display
254
- - Add `/api-docs` page to display OpenAPI documentation
255
- - Configure `zod` as the default schema tool
256
-
257
- ### 2. Generate Documentation
258
-
259
- ```bash
260
- npx next-openapi-gen generate
261
- ```
262
-
263
- This command will generate OpenAPI documentation based on your API code:
264
-
265
- - Scan API directories for routes
266
- - Analyze types/schemas
267
- - Generate OpenAPI file (`openapi.json`) in specified output directory (default: `public` folder)
268
- - Create Scalar/Swagger UI endpoint and page (if enabled)
269
-
270
- ### 3. View API Documentation
271
-
272
- To see API documenation go to `http://localhost:3000/api-docs`
273
-
274
- ## Examples
275
-
276
- ### Path Parameters
277
-
278
- ```typescript
279
- // src/app/api/users/[id]/route.ts
280
-
281
- // Zod
282
- const UserParams = z.object({
283
- id: z.string().describe("User ID"),
284
- });
285
-
286
- // Or TypeScript
287
- type UserParams = {
288
- id: string; // User ID
289
- };
290
-
291
- /**
292
- * @pathParams UserParams
293
- */
294
- export async function GET() {
295
- // ...
296
- }
297
- ```
298
-
299
- ### Query Parameters
300
-
301
- ```typescript
302
- // src/app/api/users/route.ts
303
-
304
- // Zod
305
- const UsersQueryParams = z.object({
306
- page: z.number().optional().describe("Page number"),
307
- limit: z.number().optional().describe("Results per page"),
308
- search: z.string().optional().describe("Search phrase"),
309
- });
310
-
311
- // Or TypeScript
312
- type UsersQueryParams = {
313
- page?: number; // Page number
314
- limit?: number; // Results per page
315
- search?: string; // Search phrase
316
- };
317
-
318
- /**
319
- * @params UsersQueryParams
320
- */
321
- export async function GET() {
322
- // ...
323
- }
324
- ```
325
-
326
- ### Request Body
327
-
328
- ```typescript
329
- // src/app/api/users/route.ts
330
-
331
- // Zod
332
- const CreateUserBody = z.object({
333
- name: z.string().describe("Full name"),
334
- email: z.string().email().describe("Email address"),
335
- password: z.string().min(8).describe("Password"),
336
- });
337
-
338
- // Or TypeScript
339
- type CreateUserBody = {
340
- name: string; // Full name
341
- email: string; // Email address
342
- password: string; // Password
343
- };
344
-
345
- /**
346
- * @body CreateUserBody
347
- * @bodyDescription User registration data including email and password
348
- */
349
- export async function POST() {
350
- // ...
351
- }
352
- ```
353
-
354
- ### Response
355
-
356
- ```typescript
357
- // src/app/api/users/route.ts
358
-
359
- // Zod
360
- const UserResponse = z.object({
361
- id: z.string().describe("User ID"),
362
- name: z.string().describe("Full name"),
363
- email: z.string().email().describe("Email address"),
364
- createdAt: z.date().describe("Creation date"),
365
- });
366
-
367
- // Or TypeScript
368
- type UserResponse = {
369
- id: string; // User ID
370
- name: string; // Full name
371
- email: string; // Email address
372
- createdAt: Date; // Creation date
373
- };
374
-
375
- /**
376
- * @response UserResponse
377
- * @responseDescription Returns newly created user object
378
- */
379
- export async function GET() {
380
- // ...
381
- }
382
-
383
- // Alternative formats with inline description
384
- /**
385
- * @response UserResponse:Returns user profile data
386
- */
387
- export async function GET() {
388
- // ...
389
- }
390
-
391
- /**
392
- * @response 201:UserResponse:Returns newly created user
393
- */
394
- export async function POST() {
395
- // ...
396
- }
397
-
398
- /**
399
- * @response 204:Empty:User successfully deleted
400
- */
401
- export async function DELETE() {
402
- // ...
403
- }
404
- ```
405
-
406
- ### Authorization
407
-
408
- ```typescript
409
- // src/app/api/protected/route.ts
410
-
411
- /**
412
- * @auth bearer
413
- */
414
- export async function GET() {
415
- // ...
416
- }
417
- ```
418
-
419
- ### Deprecated
420
-
421
- ```typescript
422
- // src/app/api/v1/route.ts
423
-
424
- // Zod
425
- const UserSchema = z.object({
426
- id: z.string(),
427
- name: z.string(),
428
- fullName: z.string().optional().describe("@deprecated Use name instead"),
429
- email: z.string().email(),
430
- });
431
-
432
- // Or TypeScript
433
- type UserResponse = {
434
- id: string;
435
- name: string;
436
- /** @deprecated Use firstName and lastName instead */
437
- fullName?: string;
438
- email: string;
439
- };
440
-
441
- /**
442
- * @body UserSchema
443
- * @response UserResponse
444
- */
445
- export async function GET() {
446
- // ...
447
- }
448
- ```
449
-
450
- ### Custom Operation ID
451
-
452
- ```typescript
453
- // src/app/api/users/[id]/route.ts
454
-
455
- /**
456
- * Get user by ID
457
- * @operationId getUserById
458
- * @pathParams UserParams
459
- * @response UserResponse
460
- */
461
- export async function GET() {
462
- // ...
463
- }
464
- // Generates: operationId: "getUserById" instead of auto-generated "get-users-{id}"
465
- ```
466
-
467
- ### File Uploads / Multipart Form Data
468
-
469
- ```typescript
470
- // src/app/api/upload/route.ts
471
-
472
- // Zod
473
- const FileUploadSchema = z.object({
474
- file: z.custom<File>().describe("Image file (PNG/JPG)"),
475
- description: z.string().optional().describe("File description"),
476
- category: z.string().describe("File category"),
477
- });
478
-
479
- // Or TypeScript
480
- type FileUploadFormData = {
481
- file: File;
482
- description?: string;
483
- category: string;
484
- };
485
-
486
- /**
487
- * @body FileUploadSchema
488
- * @contentType multipart/form-data
489
- */
490
- export async function POST() {
491
- // ...
492
- }
493
- ```
494
-
495
- ## Response Management
496
-
497
- ### Zero Config + Response Sets
498
-
499
- Configure reusable error sets in `next.openapi.json`:
500
-
501
- ```json
502
- {
503
- "defaultResponseSet": "common",
504
- "responseSets": {
505
- "common": ["400", "401", "500"],
506
- "public": ["400", "500"],
507
- "auth": ["400", "401", "403", "500"]
508
- }
509
- }
510
- ```
511
-
512
- ### Usage Examples
513
-
514
- ```typescript
515
- /**
516
- * Auto-default responses
517
- * @response UserResponse
518
- * @openapi
519
- */
520
- export async function GET() {}
521
- // Generates: 200:UserResponse + common errors (400, 401, 500)
522
-
523
- /**
524
- * With custom description inline
525
- * @response UserResponse:Complete user profile information
526
- * @openapi
527
- */
528
- export async function GET() {}
529
- // Generates: 200:UserResponse (with custom description) + common errors
530
-
531
- /**
532
- * Override response set
533
- * @response ProductResponse
534
- * @responseSet public
535
- * @openapi
536
- */
537
- export async function GET() {}
538
- // Generates: 200:ProductResponse + public errors (400, 500)
539
-
540
- /**
541
- * Add custom responses with description
542
- * @response 201:UserResponse:User created successfully
543
- * @add 409:ConflictResponse
544
- * @openapi
545
- */
546
- export async function POST() {}
547
- // Generates: 201:UserResponse (with custom description) + common errors + 409:ConflictResponse
548
-
549
- /**
550
- * Combine multiple sets
551
- * @response UserResponse
552
- * @responseSet auth,crud
553
- * @add 429:RateLimitResponse
554
- * @openapi
555
- */
556
- export async function PUT() {}
557
- // Combines: auth + crud errors + custom 429
558
- ```
559
-
560
- ### Error Schema Configuration
561
-
562
- #### Define consistent error schemas using templates:
563
-
564
- ```json
565
- {
566
- "defaultResponseSet": "common",
567
- "responseSets": {
568
- "common": ["400", "500"],
569
- "auth": ["400", "401", "403", "500"],
570
- "public": ["400", "500"]
571
- },
572
- "errorConfig": {
573
- "template": {
574
- "type": "object",
575
- "properties": {
576
- "error": {
577
- "type": "string",
578
- "example": "{{ERROR_MESSAGE}}"
579
- },
580
- "code": {
581
- "type": "string",
582
- "example": "{{ERROR_CODE}}"
583
- }
584
- }
585
- },
586
- "codes": {
587
- "400": {
588
- "description": "Bad Request",
589
- "variables": {
590
- "ERROR_MESSAGE": "Invalid request parameters",
591
- "ERROR_CODE": "BAD_REQUEST"
592
- }
593
- },
594
- "401": {
595
- "description": "Unauthorized",
596
- "variables": {
597
- "ERROR_MESSAGE": "Authentication required",
598
- "ERROR_CODE": "UNAUTHORIZED"
599
- }
600
- },
601
- "403": {
602
- "description": "Forbidden",
603
- "variables": {
604
- "ERROR_MESSAGE": "Access denied",
605
- "ERROR_CODE": "FORBIDDEN"
606
- }
607
- },
608
- "404": {
609
- "description": "Not Found",
610
- "variables": {
611
- "ERROR_MESSAGE": "Resource not found",
612
- "ERROR_CODE": "NOT_FOUND"
613
- }
614
- },
615
- "500": {
616
- "description": "Internal Server Error",
617
- "variables": {
618
- "ERROR_MESSAGE": "An unexpected error occurred",
619
- "ERROR_CODE": "INTERNAL_ERROR"
620
- }
621
- }
622
- }
623
- }
624
- }
625
- ```
626
-
627
- ## Ignoring Routes
628
-
629
- You can exclude routes from OpenAPI documentation in two ways:
630
-
631
- ### Using @ignore Tag
632
-
633
- Add the `@ignore` tag to any route you want to exclude:
634
-
635
- ```typescript
636
- // src/app/api/internal/route.ts
637
-
638
- /**
639
- * Internal route - not for documentation
640
- * @ignore
641
- */
642
- export async function GET() {
643
- // This route will not appear in OpenAPI documentation
644
- }
645
- ```
646
-
647
- ### Using ignoreRoutes Configuration
648
-
649
- Add patterns to your `next.openapi.json` configuration file to exclude multiple routes at once:
650
-
651
- ```json
652
- {
653
- "openapi": "3.0.0",
654
- "info": {
655
- "title": "Next.js API",
656
- "version": "1.0.0"
657
- },
658
- "apiDir": "src/app/api",
659
- "ignoreRoutes": ["/internal/*", "/debug", "/admin/test/*"]
660
- }
661
- ```
662
-
663
- Pattern matching supports wildcards:
664
-
665
- - `/internal/*` - Ignores all routes under `/internal/`
666
- - `/debug` - Ignores only the `/debug` route
667
- - `/admin/*/temp` - Ignores routes like `/admin/users/temp`, `/admin/posts/temp`
668
-
669
- ## Advanced Usage
670
-
671
- ### Automatic Path Parameter Detection
672
-
673
- The library automatically detects path parameters and generates documentation for them:
674
-
675
- ```typescript
676
- // src/app/api/users/[id]/posts/[postId]/route.ts
677
-
678
- // Will automatically detect 'id' and 'postId' parameters
679
- export async function GET() {
680
- // ...
681
- }
682
- ```
683
-
684
- If no type/schema is provided for path parameters, a default schema will be generated.
685
-
686
- ### Intelligent Examples
687
-
688
- The library generates intelligent examples for parameters based on their name:
689
-
690
- | Parameter name | Example |
691
- | -------------- | ---------------------------------------- |
692
- | `id`, `*Id` | `"123"` or `123` |
693
- | `slug` | `"example-slug"` |
694
- | `uuid` | `"123e4567-e89b-12d3-a456-426614174000"` |
695
- | `email` | `"user@example.com"` |
696
- | `name` | `"example-name"` |
697
- | `date` | `"2023-01-01"` |
698
-
699
- ### TypeScript Generics Support
700
-
701
- The library supports TypeScript generic types and automatically resolves them during documentation generation:
702
-
703
- ```typescript
704
- // src/app/api/llms/route.ts
705
-
706
- import { NextResponse } from "next/server";
707
-
708
- // Define generic response wrapper
709
- type MyApiSuccessResponseBody<T> = T & {
710
- success: true;
711
- httpCode: string;
712
- };
713
-
714
- // Define specific response data
715
- type LLMSResponse = {
716
- llms: Array<{
717
- id: string;
718
- name: string;
719
- provider: string;
720
- isDefault: boolean;
721
- }>;
722
- };
723
-
724
- /**
725
- * Get list of available LLMs
726
- * @description Get list of available LLMs with success wrapper
727
- * @response 200:MyApiSuccessResponseBody<LLMSResponse>
728
- * @openapi
729
- */
730
- export async function GET() {
731
- return NextResponse.json({
732
- success: true,
733
- httpCode: "200",
734
- llms: [
735
- {
736
- id: "gpt-5",
737
- name: "GPT-5",
738
- provider: "OpenAI",
739
- isDefault: true,
740
- },
741
- ],
742
- });
743
- }
744
- ```
745
-
746
- ### TypeScript Utility Types Support
747
-
748
- The library supports TypeScript utility types for extracting types from functions:
749
-
750
- ```typescript
751
- // src/app/api/products/route.utils.ts
752
- export async function getProductById(id: string): Promise<{
753
- product: Product;
754
- fetchedAt: string;
755
- }> {
756
- // Implementation...
757
- }
758
-
759
- export function createProduct(
760
- data: { name: string; price: number },
761
- options: { notify: boolean }
762
- ): { success: boolean; productId: string } {
763
- // Implementation...
764
- }
765
-
766
- // src/types/product-types.ts
767
-
768
- // Extract return type from async functions
769
- export type ProductResponse = Awaited<ReturnType<typeof getProductById>>;
770
-
771
- // Extract return type from sync functions
772
- export type CreateResult = ReturnType<typeof createProduct>;
773
-
774
- // Extract parameter types as tuple
775
- export type CreateProductParams = Parameters<typeof createProduct>;
776
-
777
- // Extract specific parameter using indexed access
778
- export type ProductData = Parameters<typeof createProduct>[0];
779
- export type ProductOptions = Parameters<typeof createProduct>[1];
780
-
781
- // Use with generic types
782
- interface ApiResponse<T> {
783
- success: boolean;
784
- data: T;
785
- }
786
-
787
- export type ProductApiResponse = ApiResponse<ProductResponse>;
788
-
789
- /**
790
- * @response ProductApiResponse
791
- * @openapi
792
- */
793
- export async function GET() {
794
- // Fully typed response automatically documented
795
- }
796
- ```
797
-
798
- **Supported utility types:**
799
- - `Awaited<T>` - Unwraps Promise types
800
- - `ReturnType<typeof func>` - Extracts function return type
801
- - `Parameters<typeof func>` - Extracts function parameters as tuple
802
- - `Parameters<typeof func>[N]` - Indexed access to specific parameter
803
- - Generic interfaces like `ApiResponse<T>` with type parameter substitution
804
-
805
- ## Advanced Zod Features
806
-
807
- The library supports advanced Zod features such as:
808
-
809
- ### Validation Chains
810
-
811
- ```typescript
812
- // Zod validation chains are properly converted to OpenAPI schemas
813
- const EmailSchema = z
814
- .string()
815
- .email()
816
- .min(5)
817
- .max(100)
818
- .describe("Email address");
819
-
820
- // Converts to OpenAPI with email format, minLength and maxLength
821
- ```
822
-
823
- ### Type Aliases with z.infer
824
-
825
- ```typescript
826
- // You can use TypeScript with Zod types
827
- import { z } from "zod";
828
-
829
- const UserSchema = z.object({
830
- id: z.string().uuid(),
831
- name: z.string().min(2),
832
- });
833
-
834
- // Use z.infer to create a TypeScript type
835
- type User = z.infer<typeof UserSchema>;
836
-
837
- // The library will be able to recognize this schema by reference `UserSchema` or `User` type.
838
- ```
839
-
840
- ### Factory Functions (Schema Generators)
841
-
842
- The library automatically detects and expands Zod factory functions - any function that returns a Zod schema:
843
-
844
- ```typescript
845
- // Define reusable schema factory
846
- export function createPaginatedSchema<T extends z.ZodTypeAny>(dataSchema: T) {
847
- return z.object({
848
- data: z.array(dataSchema).describe("Array of items"),
849
- pagination: z.object({
850
- nextCursor: z.string().nullable(),
851
- hasMore: z.boolean(),
852
- limit: z.number().int().positive(),
853
- }),
854
- });
855
- }
856
-
857
- // Use in your schemas - automatically expanded in OpenAPI
858
- export const PaginatedUsersSchema = createPaginatedSchema(UserSchema);
859
- export const PaginatedProductsSchema = createPaginatedSchema(ProductSchema);
860
- ```
861
-
862
- Factory functions work with any naming convention and support:
863
- - Generic type parameters
864
- - Inline schemas as arguments
865
- - Imported schemas
866
- - Multiple factory patterns in the same project
867
-
868
- ### Schema Composition with `.extend()`
869
-
870
- Zod's `.extend()` method allows you to build upon existing schemas:
871
-
872
- ```typescript
873
- // src/schemas/user.ts
874
-
875
- // Base user schema
876
- export const BaseUserSchema = z.object({
877
- id: z.string().uuid().describe("User ID"),
878
- email: z.string().email().describe("Email address"),
879
- });
880
-
881
- // Extend with additional fields
882
- export const UserProfileSchema = BaseUserSchema.extend({
883
- name: z.string().describe("Full name"),
884
- bio: z.string().optional().describe("User biography"),
885
- });
886
-
887
- // Multiple levels of extension
888
- export const AdminUserSchema = UserProfileSchema.extend({
889
- role: z.enum(["admin", "moderator"]).describe("Admin role"),
890
- permissions: z.array(z.string()).describe("Permission list"),
891
- });
892
-
893
- export const UserIdParams = z.object({
894
- id: z.string().uuid().describe("User ID"),
895
- });
896
-
897
- // src/app/api/users/[id]/route.ts
898
-
899
- /**
900
- * Get user profile
901
- * @pathParams UserIdParams
902
- * @response UserProfileSchema
903
- * @openapi
904
- */
905
- export async function GET(
906
- request: NextRequest,
907
- { params }: { params: { id: string } }
908
- ) {
909
- // Returns: { id, email, name, bio? }
910
- }
911
- ```
912
-
913
- ### Drizzle-Zod Support
914
-
915
- The library fully supports **drizzle-zod** for generating Zod schemas from Drizzle ORM table definitions. This provides a single source of truth for your database schema, validation, and API documentation.
916
-
917
- **Supported Functions:**
918
-
919
- - `createInsertSchema()` - Generate schema for inserts
920
- - `createSelectSchema()` - Generate schema for selects
921
- - `createUpdateSchema()` - Generate schema for updates
922
-
923
- **Features:**
924
-
925
- - ✅ Automatic field extraction from refinements
926
- - ✅ Validation method conversion (min, max, email, url, etc.)
927
- - ✅ Optional/nullable field detection
928
- - ✅ Intelligent type mapping based on field names
929
- - ✅ Full OpenAPI schema generation
930
-
931
- **Example:**
932
-
933
- ```typescript
934
- import { createInsertSchema } from "drizzle-zod";
935
- import { posts } from "@/db/schema";
936
-
937
- export const CreatePostSchema = createInsertSchema(posts, {
938
- title: (schema) => schema.title.min(5).max(255),
939
- content: (schema) => schema.content.min(10),
940
- published: (schema) => schema.published.optional(),
941
- });
942
- ```
943
-
944
- See the [complete Drizzle-Zod example](./examples/next15-app-drizzle-zod) for a full working implementation with a blog API.
945
-
946
- ## Multiple Schema Types Support 🆕
947
-
948
- Use **multiple schema types simultaneously** in a single project - perfect for gradual migrations, combining hand-written schemas with generated ones (protobuf, GraphQL), or using existing OpenAPI specs.
949
-
950
- ### Configuration
951
-
952
- ```json
953
- {
954
- "schemaType": ["zod", "typescript"],
955
- "schemaDir": "./src/schemas",
956
- "schemaFiles": ["./schemas/external-api.yaml"]
957
- }
958
- ```
959
-
960
- ### Schema Resolution Priority
961
-
962
- 1. **Custom files** (highest) - from `schemaFiles` array
963
- 2. **Zod schemas** (medium) - if `"zod"` in `schemaType`
964
- 3. **TypeScript types** (fallback) - if `"typescript"` in `schemaType`
965
-
966
- ### Common Use Cases
967
-
968
- ```json
969
- // Gradual TypeScript → Zod migration
970
- { "schemaType": ["zod", "typescript"] }
971
-
972
- // Zod + protobuf schemas
973
- {
974
- "schemaType": ["zod"],
975
- "schemaFiles": ["./proto/schemas.yaml"]
976
- }
977
-
978
- // Everything together
979
- {
980
- "schemaType": ["zod", "typescript"],
981
- "schemaFiles": ["./openapi-models.yaml"]
982
- }
983
- ```
984
-
985
- Custom schema files support YAML/JSON in OpenAPI 3.0 format. See **[next15-app-mixed-schemas](./examples/next15-app-mixed-schemas)** for a complete working example.
986
-
987
- ## Examples
988
-
989
- Explore complete demo projects in the **[examples](./examples/)** directory, covering integrations with Zod, TypeScript, Drizzle and documentation tools like Scalar and Swagger.
990
-
991
- ### 🚀 Run an Example
992
-
993
- ```bash
994
- cd examples/next15-app-zod
995
- npm install
996
- npx next-openapi-gen generate
997
- npm run dev
998
- ```
999
-
1000
- Then open `http://localhost:3000/api-docs` to view the generated docs.
1001
-
1002
- ## Available UI providers
1003
-
1004
- <div align="center">
1005
- <table>
1006
- <thead>
1007
- <th>Scalar</th>
1008
- <th>Swagger</th>
1009
- <th>Redoc</th>
1010
- <th>Stoplight Elements</th>
1011
- <th>RapiDoc</th>
1012
- </thead>
1013
- <tbody>
1014
- <tr>
1015
- <td>
1016
- <img width="320" alt="scalar" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/scalar.png" alt-text="scalar">
1017
- </td>
1018
- <td>
1019
- <img width="320" alt="swagger" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/swagger.png" alt-text="swagger">
1020
- </td>
1021
- <td>
1022
- <img width="320" alt="redoc" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/redoc.png" alt-text="redoc">
1023
- </td>
1024
- <td>
1025
- <img width="320" alt="stoplight" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/stoplight.png" alt-text="stoplight">
1026
- </td>
1027
- <td>
1028
- <img width="320" alt="rapidoc" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/rapidoc.png" alt-text="rapidoc">
1029
- </td>
1030
- </tr>
1031
- </tbody>
1032
- </table>
1033
- </div>
1034
-
1035
- ## Contributing
1036
-
1037
- We welcome contributions! 🎉
1038
-
1039
- Please read our [Contributing Guide](CONTRIBUTING.md) for details.
1040
-
1041
- ## Changelog
1042
-
1043
- See [CHANGELOG.md](CHANGELOG.md) for release history and changes.
1044
-
1045
- ## License
1046
-
1047
- MIT
1
+ # next-openapi-gen
2
+
3
+ [![npm version](https://img.shields.io/npm/v/next-openapi-gen)](https://www.npmjs.com/package/next-openapi-gen)
4
+ [![CI](https://github.com/tazo90/next-openapi-gen/actions/workflows/ci.yml/badge.svg)](https://github.com/tazo90/next-openapi-gen/actions/workflows/ci.yml)
5
+ [![License](https://img.shields.io/github/license/tazo90/next-openapi-gen)](https://github.com/tazo90/next-openapi-gen)
6
+
7
+ Generate OpenAPI `3.0`, `3.1`, and `3.2` from the routes and schemas you already have.
8
+
9
+ `next-openapi-gen` scans Next.js, TanStack Router, and React Router route handlers, reads JSDoc metadata, and generates an OpenAPI spec plus an optional docs UI. It is built for real codebases that use Zod, TypeScript, drizzle-zod, or reusable OpenAPI fragments, including mixed-schema migrations.
10
+
11
+ [Quick start](#quick-start) [Docs index](./docs/README.md) [Example apps](#example-apps) [Validation and coverage](#validation-and-coverage)
12
+
13
+ ## Why teams use it
14
+
15
+ - Keep OpenAPI close to your handlers instead of maintaining a separate manual spec.
16
+ - Reuse existing `zod`, `typescript`, `drizzle-zod`, and YAML/JSON OpenAPI fragments in one pipeline.
17
+ - Target `3.0`, `3.1`, or `3.2` from the same route metadata with version-aware finalization.
18
+ - Ship interactive docs quickly with built-in UI scaffolding for Scalar, Swagger, Redoc, Stoplight Elements, or RapiDoc.
19
+ - Fall back on checker-assisted App Router response inference when explicit `@response` tags are missing.
20
+
21
+ ## Quick start
22
+
23
+ ### Requirements
24
+
25
+ - Node.js `>=24`
26
+ - A supported app framework:
27
+ - Next.js using App Router or Pages Router
28
+ - TanStack Router
29
+ - React Router
30
+
31
+ ### Install
32
+
33
+ ```bash
34
+ pnpm add -D next-openapi-gen
35
+ ```
36
+
37
+ ```bash
38
+ npm install --save-dev next-openapi-gen
39
+ ```
40
+
41
+ ```bash
42
+ yarn add --dev next-openapi-gen
43
+ ```
44
+
45
+ ### Initialize and generate
46
+
47
+ ```bash
48
+ # Next.js is the default framework
49
+ pnpm exec openapi-gen init
50
+
51
+ # Or choose another supported framework
52
+ pnpm exec openapi-gen init --framework tanstack
53
+ pnpm exec openapi-gen init --framework react-router
54
+
55
+ # Scans your routes and writes the spec once
56
+ pnpm exec openapi-gen generate
57
+
58
+ # Keeps the spec fresh during local development
59
+ pnpm exec openapi-gen generate --watch
60
+ ```
61
+
62
+ > [!TIP]
63
+ > Use `--ui none` during `init` if you only want the generated OpenAPI file.
64
+ >
65
+ > The package name is still `next-openapi-gen` during the transition. Config
66
+ > discovery also accepts the new `openapi-gen.config.ts` and
67
+ > `openapi-gen.config.json` aliases, while `next-openapi.config.*` and
68
+ > `next.openapi.json` continue to work with deprecation warnings. The legacy
69
+ > `next-openapi-gen` binary still works too, but `openapi-gen` is the preferred
70
+ > CLI name going forward.
71
+
72
+ Need the full setup flow, config walkthrough, or production notes? See
73
+ [docs/getting-started.md](./docs/getting-started.md).
74
+
75
+ ### What you get
76
+
77
+ - `next.openapi.json` in your project root
78
+ - `public/openapi.json` by default
79
+ - `/api-docs` with your selected UI provider by default
80
+
81
+ ## Framework support
82
+
83
+ | Framework | Setup path | Notes |
84
+ | --------------- | ----------------------------------------------------- | -------------------------------------------------------------- |
85
+ | Next.js | `pnpm exec openapi-gen init` | Supports App Router and Pages Router |
86
+ | TanStack Router | `pnpm exec openapi-gen init --framework tanstack` | Uses the public `next-openapi-gen/vite` plugin surface |
87
+ | React Router | `pnpm exec openapi-gen init --framework react-router` | Uses the public `next-openapi-gen/react-router` plugin surface |
88
+
89
+ ## Minimal example
90
+
91
+ ```ts
92
+ import { NextRequest } from "next/server";
93
+ import { z } from "zod";
94
+
95
+ export const ProductParams = z.object({
96
+ id: z.string().describe("Product ID"),
97
+ });
98
+
99
+ export const ProductResponse = z.object({
100
+ id: z.string(),
101
+ name: z.string(),
102
+ price: z.number().positive(),
103
+ });
104
+
105
+ /**
106
+ * Get product information
107
+ * @description Fetch a product by ID
108
+ * @pathParams ProductParams
109
+ * @response ProductResponse
110
+ * @openapi
111
+ */
112
+ export async function GET(request: NextRequest, { params }: { params: { id: string } }) {
113
+ return Response.json({ id: params.id, name: "Keyboard", price: 99 });
114
+ }
115
+ ```
116
+
117
+ ## Why `next-openapi-gen` is different
118
+
119
+ | Capability | Why it matters |
120
+ | ------------------------------------- | ----------------------------------------------------------------------------------------------------- |
121
+ | Framework-aware route scanning | Covers Next.js, TanStack Router, and React Router with one generator and shared docs story. |
122
+ | Mixed schema sources | Combine `zod`, `typescript`, `schemaFiles`, and drizzle-zod-backed schemas during gradual migrations. |
123
+ | OpenAPI `3.0` / `3.1` / `3.2` targets | Keep one authoring flow while emitting version-aware output for newer spec features. |
124
+ | Response inference | Infer typed App Router responses when `@response` is omitted, while still letting explicit tags win. |
125
+ | Docs UI scaffolding | Generate a docs page fast instead of stopping at a JSON file. |
126
+
127
+ ## Common workflows
128
+
129
+ ### Start with Zod or TypeScript
130
+
131
+ Use one schema system if your app is already consistent:
132
+
133
+ ```json
134
+ {
135
+ "schemaType": "zod",
136
+ "schemaDir": "src/schemas"
137
+ }
138
+ ```
139
+
140
+ ### Migrate gradually with mixed schema sources
141
+
142
+ Use multiple schema types in the same project when you are moving from TypeScript to Zod or merging generated and hand-authored schemas:
143
+
144
+ ```json
145
+ {
146
+ "schemaType": ["zod", "typescript"],
147
+ "schemaDir": "./src/schemas",
148
+ "schemaFiles": ["./schemas/external-api.yaml"]
149
+ }
150
+ ```
151
+
152
+ Resolution priority is:
153
+
154
+ 1. `schemaFiles`
155
+ 2. `zod`
156
+ 3. `typescript`
157
+
158
+ See [apps/next-app-mixed-schemas](./apps/next-app-mixed-schemas) for a full working example.
159
+ For more adoption patterns, see
160
+ [docs/workflows-and-integrations.md](./docs/workflows-and-integrations.md).
161
+
162
+ ### Generate docs from Drizzle schemas
163
+
164
+ `next-openapi-gen` works well with `drizzle-zod`, so your database schema, validation, and API docs can share the same source of truth.
165
+
166
+ ```ts
167
+ import { createInsertSchema, createSelectSchema } from "drizzle-zod";
168
+ import { posts } from "@/db/schema";
169
+
170
+ export const CreatePostSchema = createInsertSchema(posts, {
171
+ title: (schema) => schema.title.min(5).max(255),
172
+ content: (schema) => schema.content.min(10),
173
+ });
174
+
175
+ export const PostResponseSchema = createSelectSchema(posts);
176
+ ```
177
+
178
+ See [apps/next-app-drizzle-zod](./apps/next-app-drizzle-zod) for the full CRUD example.
179
+
180
+ ### Rely on inference when you want less annotation
181
+
182
+ If you omit `@response`, App Router handlers can infer responses from typed `NextResponse.json(...)` and `Response.json(...)` returns.
183
+
184
+ ```ts
185
+ import { NextResponse } from "next/server";
186
+
187
+ type SearchResponse = {
188
+ total: number;
189
+ };
190
+
191
+ /**
192
+ * Search events
193
+ * @responseDescription Search result
194
+ * @openapi
195
+ */
196
+ export async function POST(): Promise<NextResponse<SearchResponse>> {
197
+ return NextResponse.json({ total: 3 });
198
+ }
199
+ ```
200
+
201
+ Explicit `@response` tags still take precedence when you want stable schema names or exact response codes.
202
+
203
+ ## Configuration
204
+
205
+ `init` creates a `next.openapi.json` file like this:
206
+
207
+ ```json
208
+ {
209
+ "openapi": "3.0.0",
210
+ "info": {
211
+ "title": "Next.js API",
212
+ "version": "1.0.0",
213
+ "description": "API generated by next-openapi-gen"
214
+ },
215
+ "apiDir": "src/app/api",
216
+ "routerType": "app",
217
+ "schemaDir": "src/schemas",
218
+ "schemaType": "zod",
219
+ "schemaFiles": [],
220
+ "outputFile": "openapi.json",
221
+ "outputDir": "./public",
222
+ "docsUrl": "api-docs",
223
+ "includeOpenApiRoutes": false,
224
+ "ignoreRoutes": [],
225
+ "debug": false
226
+ }
227
+ ```
228
+
229
+ Version guidance:
230
+
231
+ - Use `3.0.0` when you want the broadest downstream tooling compatibility.
232
+ - Use `3.1.0` when you want JSON Schema 2020-12-aligned output such as `jsonSchemaDialect`.
233
+ - Use `3.2.0` when you want first-class `querystring`, enhanced tag metadata, sequential media, and richer example objects.
234
+
235
+ ### Important options
236
+
237
+ | Option | Purpose |
238
+ | ------------------------------------- | ---------------------------------------------------------------- |
239
+ | `openapi` | Target `3.0.0`, `3.1.0`, or `3.2.0` output |
240
+ | `apiDir` | Route directory to scan |
241
+ | `routerType` | `"app"` or `"pages"` |
242
+ | `schemaDir` | Directory or directories to search for schemas/types |
243
+ | `schemaType` | `"zod"`, `"typescript"`, or both |
244
+ | `schemaFiles` | YAML/JSON OpenAPI fragments to merge into the generated document |
245
+ | `includeOpenApiRoutes` | Only include handlers tagged with `@openapi` |
246
+ | `ignoreRoutes` | Exclude routes with wildcard support |
247
+ | `defaultResponseSet` / `responseSets` | Reusable error-response groups |
248
+ | `errorConfig` | Shared error schema templates |
249
+
250
+ For a fuller setup guide, Pages Router notes, response sets, and route exclusion
251
+ patterns, see [docs/getting-started.md](./docs/getting-started.md).
252
+
253
+ ## JSDoc tags you will use most
254
+
255
+ | Tag | Purpose |
256
+ | -------------------------- | ---------------------------------------------------------------- |
257
+ | `@pathParams` | Path parameter schema or type |
258
+ | `@params` / `@queryParams` | Query parameter schema or type |
259
+ | `@body` | Request body schema or type |
260
+ | `@response` | Response schema, code, and optional description |
261
+ | `@responseDescription` | Response description without redefining the schema |
262
+ | `@auth` | Security requirement(s), including comma-separated alternatives |
263
+ | `@contentType` | Request content type such as `multipart/form-data` |
264
+ | `@examples` | Request, response, and querystring examples |
265
+ | `@openapi` | Explicit inclusion marker when `includeOpenApiRoutes` is enabled |
266
+ | `@ignore` | Exclude a route from generation |
267
+ | `@method` | Required HTTP method tag for Pages Router handlers |
268
+
269
+ For the complete tag guide and usage recipes, see
270
+ [docs/jsdoc-reference.md](./docs/jsdoc-reference.md).
271
+
272
+ OpenAPI `3.2`-specific tags such as `@querystring`, `@tagSummary`, `@tagKind`,
273
+ and sequential media annotations are documented in the same guide and shown in
274
+ [apps/next-app-zod](./apps/next-app-zod).
275
+
276
+ ## Compatibility
277
+
278
+ | Area | Support |
279
+ | --------------- | ------------------------------------------------------------ |
280
+ | Frameworks | Next.js, TanStack Router, React Router |
281
+ | Next.js routers | App Router and Pages Router |
282
+ | OpenAPI targets | `3.0`, `3.1`, `3.2` |
283
+ | Schema sources | `zod`, `typescript`, drizzle-zod output, YAML/JSON fragments |
284
+ | Docs UIs | Scalar, Swagger, Redoc, Stoplight Elements, RapiDoc |
285
+
286
+ For Pages Router projects, set `routerType` to `"pages"` and annotate handlers with `@method`. See [apps/next-pages-router](./apps/next-pages-router).
287
+
288
+ For the supported Zod 4 surface and known gaps, see
289
+ [docs/zod4-support-matrix.md](./docs/zod4-support-matrix.md).
290
+
291
+ ## Framework integrations
292
+
293
+ Use the integration that matches your framework:
294
+
295
+ - `next-openapi-gen/next`: Next.js adapter helpers such as `createNextOpenApiAdapter`
296
+ - `next-openapi-gen/vite`: Vite plugin surface used by the TanStack example app
297
+ - `next-openapi-gen/react-router`: React Router plugin surface
298
+
299
+ The main package export also exposes `generateProject`, `watchProject`, and
300
+ config helpers when you want to script generation directly.
301
+
302
+ ## Example apps
303
+
304
+ Use the checked-in examples to evaluate the tool in realistic setups:
305
+
306
+ - [apps/next-app-zod](./apps/next-app-zod): Zod-first App Router example
307
+ - [apps/next-app-next-config](./apps/next-app-next-config): typed config example targeting OpenAPI `3.1`
308
+ - [apps/next-app-typescript](./apps/next-app-typescript): TypeScript-first example
309
+ - [apps/next-app-mixed-schemas](./apps/next-app-mixed-schemas): mixed schema migration example
310
+ - [apps/next-app-drizzle-zod](./apps/next-app-drizzle-zod): Drizzle + drizzle-zod CRUD example
311
+ - [apps/next-app-sandbox](./apps/next-app-sandbox): edge-case route and exclusion playground
312
+ - [apps/next-app-ts-config](./apps/next-app-ts-config): typed config loading example
313
+ - [apps/next-app-adapter](./apps/next-app-adapter): Next adapter integration smoke example
314
+ - [apps/next-pages-router](./apps/next-pages-router): legacy Pages Router support
315
+ - [apps/tanstack-app](./apps/tanstack-app): TanStack Router framework parity example
316
+ - [apps/react-router-app](./apps/react-router-app): React Router framework parity example
317
+ - [apps/next-app-scalar](./apps/next-app-scalar), [apps/next-app-swagger](./apps/next-app-swagger): docs UI variants
318
+
319
+ ### Run an example
320
+
321
+ ```bash
322
+ pnpm install
323
+ cd apps/next-app-zod
324
+ pnpm exec openapi-gen generate
325
+ pnpm dev
326
+ ```
327
+
328
+ Then open `http://localhost:3000/api-docs`.
329
+
330
+ ## Validation and coverage
331
+
332
+ This repo is not just a demo. The CI pipeline covers:
333
+
334
+ - formatting and linting
335
+ - workspace builds
336
+ - unit tests
337
+ - integration tests
338
+ - coverage reporting
339
+ - Playwright E2E runs across an app matrix
340
+
341
+ For the detailed version matrix and validation notes, see:
342
+
343
+ - [docs/openapi-version-coverage.md](./docs/openapi-version-coverage.md)
344
+ - [docs/zod4-support-matrix.md](./docs/zod4-support-matrix.md)
345
+
346
+ The checked-in examples intentionally span different goals: most apps stay on
347
+ `3.0` as the conservative default, `apps/next-app-next-config` demonstrates a
348
+ typed `3.1` config, and `apps/next-app-zod` showcases richer `3.2` route and
349
+ document features.
350
+
351
+ ## Available UI providers
352
+
353
+ | Scalar | Swagger | Redoc | Stoplight Elements | RapiDoc |
354
+ | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
355
+ | ![Scalar UI](https://raw.githubusercontent.com/tazo90/next-openapi-gen/main/assets/scalar.png) | ![Swagger UI](https://raw.githubusercontent.com/tazo90/next-openapi-gen/main/assets/swagger.png) | ![Redoc UI](https://raw.githubusercontent.com/tazo90/next-openapi-gen/main/assets/redoc.png) | ![Stoplight Elements UI](https://raw.githubusercontent.com/tazo90/next-openapi-gen/main/assets/stoplight.png) | ![RapiDoc UI](https://raw.githubusercontent.com/tazo90/next-openapi-gen/main/assets/rapidoc.png) |
356
+
357
+ ## Advanced docs
358
+
359
+ Use these deeper references when you need more than the quick start:
360
+
361
+ - [docs/README.md](./docs/README.md): docs index
362
+ - [docs/getting-started.md](./docs/getting-started.md): setup, config, framework defaults, watch mode, and production notes
363
+ - [docs/jsdoc-reference.md](./docs/jsdoc-reference.md): full route tag reference and examples
364
+ - [docs/workflows-and-integrations.md](./docs/workflows-and-integrations.md): framework integrations, mixed schemas, drizzle-zod, and downstream workflows
365
+ - [docs/faq.md](./docs/faq.md): troubleshooting and common questions
366
+ - [docs/openapi-version-coverage.md](./docs/openapi-version-coverage.md): version-specific behavior, validation strategy, and generated vs preserved fields
367
+ - [docs/zod4-support-matrix.md](./docs/zod4-support-matrix.md): tested Zod 4 coverage and known boundaries
368
+ - [docs/example-app-coverage-plan.md](./docs/example-app-coverage-plan.md): example app roles, coverage goals, and expansion roadmap
369
+ - [apps](./apps): complete runnable examples
370
+
371
+ ## CLI
372
+
373
+ ```bash
374
+ pnpm exec openapi-gen init
375
+ pnpm exec openapi-gen generate
376
+ pnpm exec openapi-gen generate --watch
377
+ ```
378
+
379
+ ### `init` options
380
+
381
+ | Option | Choices | Default |
382
+ | ------------- | ------------------------------------------------------------ | ------------------- |
383
+ | `--framework` | `next`, `tanstack`, `react-router` | `next` |
384
+ | `--ui` | `scalar`, `swagger`, `redoc`, `stoplight`, `rapidoc`, `none` | `scalar` |
385
+ | `--schema` | `zod`, `typescript` | `zod` |
386
+ | `--docs-url` | any string | `api-docs` |
387
+ | `--output` | any path | `next.openapi.json` |
388
+
389
+ ### `generate` options
390
+
391
+ | Option | Purpose |
392
+ | ------------ | --------------------------------------------- |
393
+ | `--config` | Use a specific config file |
394
+ | `--template` | Merge a specific OpenAPI template or fragment |
395
+ | `--watch` | Regenerate when routes or schema files change |
396
+
397
+ ## Contributing
398
+
399
+ Contributions are welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup, commit conventions, and workflow details.
400
+
401
+ ## Changelog
402
+
403
+ See [CHANGELOG.md](./CHANGELOG.md) for release history and recent changes.
404
+
405
+ ## License
406
+
407
+ MIT