omar-dulaimi/prisma-orpc-generator(新しいタブで開きます)
主要言語: TypeScript
Prisma generator that creates fully-featured oRPC routers
- star 数
- 38
- watcher 数
- 0
- fork 数
- 3
- issue 数
- 0
- 最終更新
- 2026/07/29
主要言語: TypeScript
Prisma generator that creates fully-featured oRPC routers
Generate typed oRPC routers, Zod schemas, and docs straight from your Prisma schema.
Prisma v7+, Node 20.19+/22.12+/24.0+, TypeScript ≥ 5.4.
TL;DR: Add the generator to your Prisma schema and run Prisma generate. That’s it.
generator client { provider = "prisma-client-js" } generator orpc { provider = "prisma-orpc-generator" output = "./src/generated/orpc" // Optional config (booleans are strings) schemaLibrary = "zod" generateInputValidation = "true" generateOutputValidation = "true" // Shield authorization (optional) generateShield = "true" defaultReadRule = "allow" defaultWriteRule = "auth" }
Create prisma.config.ts to hold your datasource connection (replace the URL for your database or driver adapter):
import { defineConfig } from '@prisma/config'; export default defineConfig({ schema: './schema.prisma', datasource: { url: 'file:./dev.db', }, });
# generate
npx prisma generate --config prisma.config.tsPrerequisites
Install
The generator itself and the Prisma CLI are build-time only. Everything the generated routers
import has to be a runtime dependency of your app: @orpc/server, zod, @prisma/client, and
orpc-shield (the generated shield.ts and createRouter.ts import it, and shield generation is
on by default; drop it only if you set generateShield = "false").
# npm npm install @orpc/server orpc-shield zod @prisma/client npm install -D prisma-orpc-generator prisma # pnpm pnpm add @orpc/server orpc-shield zod @prisma/client pnpm add -D prisma-orpc-generator prisma # yarn yarn add @orpc/server orpc-shield zod @prisma/client yarn add -D prisma-orpc-generator prisma
Serving the routers over HTTP additionally needs a handler package, e.g. @orpc/openapi for the
OpenAPI server shown further down.
Add the generator (minimal)
generator client { provider = "prisma-client-js" } generator orpc { provider = "prisma-orpc-generator" output = "./src/generated/orpc" }
Generate
npx prisma generate --config prisma.config.ts
src/generated/orpc/
├─ routers/
│ ├─ models/ # per-model routers
│ └─ helpers/ # common utilities
├─ tests/ # generated tests
├─ zod-schemas/ # zod (if enabled)
└─ documentation/ # docs (if enabled)
Explore the example outputs:
Tip: Browse the example’s generated root for real structure: examples/basic/src/generated/orpc.
Validated against src/config/schema.ts. Below are the most commonly used options.
Core options
| Option | Type | Default | Values | Description |
|---|---|---|---|---|
| output | string | ./src/generated/orpc | any | Directory for generated oRPC artifacts |
| schemaLibrary | enum | "zod" | zod | Schema validation library |
| generateInputValidation | boolean (string) | "true" | "true", "false" | Emit Zod validation for inputs |
| generateOutputValidation | boolean (string) | "true" | "true", "false" | Emit Zod validation for outputs |
| strictValidation | boolean (string) | "true" | "true", "false" | Stricter Zod shapes for safety |
| zodSchemasOutputPath | string | ./zod-schemas | any | Relative path (under output) for Zod files |
| externalZodImportPath | string | ./zod-schemas | any | Module/path used when importing Zod schemas |
| zodDateTimeStrategy | enum | "coerce" | "date", "coerce", "isoString" | How DateTime fields are modeled in Zod |
| zodConfigPath | string | none | any | Path to custom zod.config.json file (relative to schema or absolute) |
Operational options
| Option | Type | Default | Values | Description |
|---|---|---|---|---|
| generateModelActions | string list | all | see note | Comma-separated actions to emit (see note below) |
| showModelNameInProcedure | boolean (string) | "true" | "true", "false" | Prefix procedures with model name |
| enableSoftDeletes | boolean (string) | "false" | "true", "false" | Add soft-delete semantics where applicable |
| generateRelationResolvers | boolean (string) | "true" | "true", "false" | Emit helpers to resolve relations |
| wrapResponses | boolean (string) | "false" | "true", "false" | Wrap handler results in an envelope |
DX and formatting
| Option | Type | Default | Values | Description |
|---|---|---|---|---|
| useBarrelExports | boolean (string) | "true" | "true", "false" | Generate index.ts barrel exports |
| codeStyle | enum | "prettier" | "prettier", "none" | Format generated code with Prettier |
| generateDocumentation | boolean (string) | "false" | "true", "false" | Generate API documentation |
| generateTests | boolean (string) | "false" | "true", "false" | Generate test files |
| enableDebugLogging | boolean (string) | "false" | "true", "false" | Extra logs during generation |
Runtime and integration
| Option | Type | Default | Values | Description |
|---|---|---|---|---|
| prismaClientPath | string | @prisma/client | any | Import path for PrismaClient |
| contextPath | string | "" | any | Optional path to your app's Context module |
| serverPort | number (string) | 3000 | any | Port used by optional docs/server helpers |
| apiPrefix | string | "" | any | Prefix used by optional docs/server helpers |
| apiTitle | string | Generated API | any | API title for documentation |
| apiDescription | string | Auto-generated API from Prisma schema | any | API description for documentation |
| apiVersion | string | 1.0.0 | any | API version for documentation |
Shield / Authorization
| Option | Type | Default | Values | Description |
|---|---|---|---|---|
| generateShield | boolean (string) | "true" | "true", "false" | Enable shield generation |
| shieldPath | string | none | any | Path to custom shield file (absolute, relative to project root, relative to output dir, or module specifier) |
| defaultReadRule | enum | "allow" | "allow", "deny", "auth" | Default rule for read operations |
| defaultWriteRule | enum | "auth" | "auth", "deny", "allow" | Default rule for write operations |
| denyErrorCode | string | "FORBIDDEN" | any | Error code for denied access |
| debug | boolean (string) | "false" | "true", "false" | Enable debug logging |
| allowExternalErrors | boolean (string) | "false" | "true", "false" | Allow detailed error messages from shields |
| Notes |
generator orpc { provider = "prisma-orpc-generator" output = "./src/generated/orpc" schemaLibrary = "zod" zodDateTimeStrategy = "coerce" generateInputValidation = "true" generateOutputValidation = "true" generateDocumentation = "true" useBarrelExports = "true" codeStyle = "prettier" }
This generator leverages prisma-zod-generator to create Zod schemas from your Prisma models. Here's how the process works:
schemaLibrary = "zod" is set, the generator automatically calls prisma-zod-generatorzod.config.json file with optimized settings for oRPC usagezod-schemas/ subdirectory of your output pathThe generator creates a minimal zod.config.json file:
{
"mode": "full",
"output": "./zod-schemas"
}Additional settings are only added when they differ from defaults:
{
"mode": "full",
"output": "./zod-schemas",
"dateTimeStrategy": "date"
}The zodDateTimeStrategy option controls how Prisma DateTime fields are modeled in Zod schemas:
| Strategy | Zod Schema | Description | prisma-zod-generator equivalent |
|---|---|---|---|
"coerce" (default) |
z.coerce.date() |
Automatically converts strings/numbers to Date objects | dateTimeStrategy: "coerce" |
"date" |
z.date() |
Requires actual Date objects, no conversion | dateTimeStrategy: "date" |
"isoString" |
z.string().regex(ISO).transform() |
Validates ISO string format, transforms to Date | dateTimeStrategy: "isoString" |
For advanced use cases, you can provide your own zod.config.json:
generator orpc { provider = "prisma-orpc-generator" output = "./src/generated/orpc" zodConfigPath = "./custom-zod.config.json" // Path to your config file }
When zodConfigPath is specified:
Generated Zod schemas follow this structure:
src/generated/orpc/
├─ zod-schemas/
│ ├─ index.ts # Barrel exports
│ ├─ objects/ # Model schemas
│ │ ├─ UserSchema.ts
│ │ └─ PostSchema.ts
│ └─ inputTypeSchemas/ # Input validation schemas
│ ├─ UserCreateInput.ts
│ └─ UserUpdateInput.ts
└─ routers/ # oRPC routers (import from ../zod-schemas)
The generator can automatically generate orpc-shield configurations for type-safe authorization. Shield provides declarative rules, composable operators, and path-based permissions.
Add shield options to your generator config:
generator orpc { provider = "prisma-orpc-generator" output = "./src/generated/orpc" // Enable shield generation generateShield = "true" // Option 1: Auto-generate shield rules defaultReadRule = "allow" // "allow", "deny", "auth" defaultWriteRule = "auth" // "auth", "deny" // Option 2: Use custom shield file (relative to output dir) // shieldPath = "../auth/my-custom-shield" // Error handling denyErrorCode = "FORBIDDEN" debug = "false" }
Shield generation creates:
src/generated/orpc/
├─ shield.ts # Shield rules and permissions (auto-generated)
├─ routers/
│ ├─ index.ts # App router with shield exports
│ └─ helpers/
│ └─ createRouter.ts # Base router with shield middleware integration
When shieldPath is provided: The generator skips auto-generation and dynamically integrates your custom shield file into the generated middleware chain.
The generator now features smart dynamic path resolution for shield files. When you specify a shieldPath, the generator automatically:
Example Generated Integration:
// In src/generated/orpc/routers/helpers/createRouter.ts import { permissions } from '../../../../custom-shield'; export const or = os.$context<Context>().use(permissions);
For advanced use cases, you can provide your own shield file instead of auto-generation:
generator orpc { provider = "prisma-orpc-generator" output = "./src/generated/orpc" generateShield = "true" shieldPath = "../../src/custom-shield" // Dynamically resolved! }
Supported Path Formats:
"../../src/auth/shield""src/auth/shield""/absolute/path/to/shield"Your custom shield file should export a permissions object:
// src/custom-shield.ts import { rule, allow, deny, shield, or } from 'orpc-shield'; import type { Context } from '../generated/orpc/routers/helpers/createRouter'; const isAuthenticated = rule<Context>()(({ ctx }) => !!ctx.user); const isAdmin = rule<Context>()(({ ctx }) => ctx.user?.role === 'admin'); const isOwner = rule<Context>()(({ ctx, input }) => { return ctx.user?.id === (input as any)?.userId; }); export const permissions = shield<Context>({ user: { userFindMany: allow, // Match generated procedure names userCreate: isAuthenticated, userUpdate: isAuthenticated, userDelete: or(isAdmin, isOwner), userDeleteMany: deny, // Explicitly deny dangerous operations }, post: { postFindMany: allow, postCreate: isAuthenticated, postUpdate: isAuthenticated, postDelete: isAuthenticated, }, }, { denyErrorCode: 'FORBIDDEN', // Maps to HTTP 403 debug: true, // Enable debug logging allowExternalErrors: true, // Allow detailed error messages });
Important: Shield procedure names should match your generated router names (e.g., userCreate, postFindMany).
Note: When using shieldPath, the generator will skip auto-generation and use your custom shield file instead.
The generator creates rules based on your Prisma models:
// Built-in rules (generated automatically) const isAuthenticated = rule<Context>()(({ ctx }) => !!ctx.user); // Example custom rules (user-defined) const isAdmin = rule<Context>()(({ ctx }) => ctx.user?.role === 'admin'); // Model-specific rules (generated based on config) const canReadUser = allow; // Read operations: allow const canWriteUser = isAuthenticated; // Write operations: require auth // Shield configuration export const permissions = shield<Context>({ user: { list: canReadUser, findById: canReadUser, create: canWriteUser, update: canWriteUser, delete: canWriteUser, }, post: { list: allow, create: isAuthenticated, update: isAuthenticated, }, });
Import and use the generated shield:
import { appRouter, permissions } from './generated/orpc/routers'; // Apply shield at server level const server = createServer(appRouter, { // Shield is applied via middleware middleware: [permissions] }); // Or use with oRPC handlers import { OpenAPIHandler } from '@orpc/openapi'; const handler = new OpenAPIHandler(appRouter, { // Shield permissions are automatically applied interceptors: [/* your interceptors */] });
Shield rules expect a Context with user information:
interface Context { prisma: PrismaClient; user?: { id: string; email?: string; name?: string; roles?: string[]; permissions?: string[]; }; }
Override default rules by modifying the generated shield.ts:
// Custom rule for post ownership const isPostOwner = rule<Context>()(({ ctx, input }) => { return ctx.user?.id === (input as any)?.authorId; }); // Use in shield config const permissions = shield<Context>({ post: { update: and(isAuthenticated, isPostOwner), // Auth + ownership delete: or(isAdmin, isPostOwner), // Admin or owner }, });
| Option | Type | Default | Values | Description |
|---|---|---|---|---|
| generateShield | boolean (string) | "true" | "true", "false" | Enable shield generation |
| shieldPath | string | none | any | Path to custom shield file (absolute, relative to project root, relative to output dir, or module specifier) |
| defaultReadRule | enum | "allow" | "allow", "deny", "auth" | Default rule for read operations |
| defaultWriteRule | enum | "auth" | "auth", "deny", "allow" | Default rule for write operations |
| denyErrorCode | string | "FORBIDDEN" | any | Error code for denied access |
| debug | boolean (string) | "false" | "true", "false" | Enable debug logging |
| allowExternalErrors | boolean (string) | "false" | "true", "false" | Allow detailed error messages from shields |
What it does
Notable files
Node version or ESM issues
npm run buildGenerated path is unexpected
Schema/config validation failures
Docs not emitted
generateDocumentation = "true" and inspect src/generators/documentation-generator.tsShield path resolution errors
shieldPath points to correct file; check file exports permissions object; ensure path is relative to project root or absoluteLocal dev loop
npm run dev # watch build npm run build # one-off build npm run lint # lint npm run lint:fix # lint + fix npm run format # prettier npm run typecheck # types only
Local development (monorepo) provider example
generator orpc { provider = "../../lib/bin.js" // relative path to built generator output = "./src/generated/orpc" }
Testing
npm test # unit/integration npm run test:watch # watch npm run test:e2e # Prisma-backed CRUD npm run test:coverage # coverage
Conventions
npm run build and npm run typecheck pass before PRLICENSE file.See CHANGELOG.md
Made with ❤️ by Omar Dulaimi