An open API service indexing awesome lists of open source software.

https://github.com/omar-dulaimi/prisma-orpc-generator

Prisma generator that creates fully-featured ORPC routers
https://github.com/omar-dulaimi/prisma-orpc-generator

orpc prisma prisma-orpc-generator prisma-zod-generator zod

Last synced: 26 days ago
JSON representation

Prisma generator that creates fully-featured ORPC routers

Awesome Lists containing this project

README

          

⚑ Prisma oRPC Generator


Generate typed oRPC routers, Zod schemas, and docs straight from your Prisma schema.


npm
CI
license
node
prisma
TypeScript
Prettier

Prisma v6+, Node 18.18+/20.9+/22.11+, TypeScript β‰₯ 5.1.


> TL;DR β€” Add the generator to your Prisma schema and run Prisma generate. That’s it.

```prisma
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"
}
```

```bash
# generate
npx prisma generate
```

---

## πŸ“‹ Table of Contents

- [⚑ Quickstart](#quickstart) - Get up and running in minutes
- [πŸ—οΈ What Gets Generated](#what-gets-generated) - See what files are created
- [βš™οΈ Configuration](#configuration) - All available options
- [πŸ”§ Zod Schemas Generation](#zod-schemas-generation) - Schema validation setup
- [πŸ›‘οΈ Shield Authorization](#shield-authorization) - Type-safe permissions and rules
- [πŸ§ͺ Examples](#examples) - Working examples to explore
- [❓ FAQ / Troubleshooting](#faq--troubleshooting) - Common issues and solutions
- [πŸ§‘β€πŸ’» Development](#development-contributing) - Contributing guidelines
- [πŸ—ΊοΈ Roadmap](#roadmap) - Planned features and improvements
- [πŸ“„ License](#license) - Licensing information
- [πŸ™ Acknowledgements](#acknowledgements) - Credits and thanks
- [πŸ“ Changelog](#changelog) - Version history and changes

---


## ⚑ Quickstart

Click to expand quickstart guide

**Prerequisites**
- Node: 18.18.0+, 20.9.0+, or 22.11.0+
- Prisma CLI (v6+) in your project
- TypeScript β‰₯ 5.1.0 recommended

**Install**
```bash
# npm
npm install -D prisma-orpc-generator zod prisma @prisma/client

# pnpm
pnpm add -D prisma-orpc-generator zod prisma @prisma/client

# yarn
yarn add -D prisma-orpc-generator zod prisma @prisma/client
```

Add the generator (minimal)
```prisma
generator client {
provider = "prisma-client-js"
}

generator orpc {
provider = "prisma-orpc-generator"
output = "./src/generated/orpc"
}
```
**Generate**
```bash
npx prisma generate
```

---


## 🧩 Compatibility

Click to expand compatibility info
- Prisma ORM: v6+
- Node.js minimums for Prisma v6:
- 18.18.0+
- 20.9.0+
- 22.11.0+
- Not supported: 16, 17, 19, 21
- TypeScript: β‰₯ 5.1.0

---


## πŸ—οΈ What Gets Generated

Click to expand generated files overview
A generated surface mirroring your domain:

```
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:
- Routers: [examples/basic/src/generated/orpc/routers](examples/basic/src/generated/orpc/routers)
- Zod schemas: [examples/basic/src/generated/orpc/zod-schemas](examples/basic/src/generated/orpc/zod-schemas)
- Tests: [examples/basic/src/generated/orpc/tests](examples/basic/src/generated/orpc/tests)
- Docs: [examples/basic/src/generated/orpc/documentation](examples/basic/src/generated/orpc/documentation)

---


## πŸ› οΈ Usage

Click to expand usage guide
- Runs as part of Prisma’s generator pipeline.
- Default output directory is `./src/generated/orpc` (configurable via the generator block).
- Import the generated code into your server/app. See the runnable example server in [examples/basic/src/server.ts](examples/basic/src/server.ts).

Tip: Browse the example’s generated root for real structure: [examples/basic/src/generated/orpc](examples/basic/src/generated/orpc).

---


## βš™οΈ Configuration

Click to expand configuration options
Where configuration lives
- Inside your generator block in [schema.prisma](examples/basic/schema.prisma)
- Booleans are strings: "true"/"false"; numbers as strings are supported

Validated against [src/config/schema.ts](src/config/schema.ts). Below are the most commonly used options.

Core options
| Option | Type | Default | Values | Description |
|---|---|---|---|---|
| output | string | ./src/generated/orpc | β€” | 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 | β€” | Relative path (under output) for Zod files |
| externalZodImportPath | string | ./zod-schemas | β€” | Module/path used when importing Zod schemas |
| zodDateTimeStrategy | enum | "coerce" | "date", "coerce", "isoString" | How DateTime fields are modeled in Zod |
| zodConfigPath | string | β€” | β€” | 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 | β€” | Import path for PrismaClient |
| contextPath | string | "" | β€” | Optional path to your app's Context module |
| serverPort | number (string) | 3000 | β€” | Port used by optional docs/server helpers |
| apiPrefix | string | "" | β€” | Prefix used by optional docs/server helpers |
| apiTitle | string | Generated API | β€” | API title for documentation |
| apiDescription | string | Auto-generated API from Prisma schema | β€” | API description for documentation |
| apiVersion | string | 1.0.0 | β€” | API version for documentation |

Shield / Authorization
| Option | Type | Default | Values | Description |
|---|---|---|---|---|
| generateShield | boolean (string) | "true" | "true", "false" | Enable shield generation |
| shieldPath | string | β€” | β€” | 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" | β€” | 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
- generateModelActions supports: create, createMany, findFirst, findFirstOrThrow, findMany, findUnique, findUniqueOrThrow, update, updateMany, upsert, delete, deleteMany, aggregate, groupBy, count, findRaw, aggregateRaw.
- Booleans are strings in Prisma generator config: use "true" or "false".
- The full, authoritative shape lives in [src/config/schema.ts](src/config/schema.ts).

Example: focused configuration with Zod and docs

```prisma
generator orpc {
provider = "prisma-orpc-generator"
output = "./src/generated/orpc"

schemaLibrary = "zod"
zodDateTimeStrategy = "coerce"
generateInputValidation = "true"
generateOutputValidation = "true"
generateDocumentation = "true"
useBarrelExports = "true"
codeStyle = "prettier"
}
```

---


## πŸ”§ Zod Schemas Generation

Click to expand zod schemas info

This generator leverages [prisma-zod-generator](https://github.com/omar-dulaimi/prisma-zod-generator) to create Zod schemas from your Prisma models. Here's how the process works:

### Generation Process

1. **Automatic Integration**: When `schemaLibrary = "zod"` is set, the generator automatically calls `prisma-zod-generator`
2. **Configuration Management**: Creates a `zod.config.json` file with optimized settings for oRPC usage
3. **Schema Output**: Generates Zod schemas in the `zod-schemas/` subdirectory of your output path
4. **Import Integration**: Generated oRPC routers automatically import and use these schemas for validation

### Configuration File

The generator creates a minimal `zod.config.json` file:

```json
{
"mode": "full",
"output": "./zod-schemas"
}
```

Additional settings are only added when they differ from defaults:

```json
{
"mode": "full",
"output": "./zod-schemas",
"dateTimeStrategy": "date"
}
```

### DateTime Handling Strategy

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"` |

### Custom Zod Configuration

For advanced use cases, you can provide your own `zod.config.json`:

```prisma
generator orpc {
provider = "prisma-orpc-generator"
output = "./src/generated/orpc"

zodConfigPath = "./custom-zod.config.json" // Path to your config file
}
```

When `zodConfigPath` is specified:
- The generator uses your existing configuration
- oRPC-specific settings are passed as generator options instead of modifying the config file
- Your custom configuration takes precedence

### File Structure

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)
```

---


## πŸ›‘οΈ Shield Authorization

Click to expand shield authorization guide

The generator can automatically generate [orpc-shield](https://github.com/omar-dulaimi/orpc-shield) configurations for type-safe authorization. Shield provides declarative rules, composable operators, and path-based permissions.

### Shield Configuration

Add shield options to your generator config:

```prisma
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"
}
```

### What Gets Generated

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.

### Dynamic Shield Path Resolution ✨

The generator now features **smart dynamic path resolution** for shield files. When you specify a `shieldPath`, the generator automatically:

- βœ… **Resolves relative paths** from your project structure
- βœ… **Handles different output directory layouts**
- βœ… **Integrates shield middleware** using the proper oRPC pattern
- βœ… **Generates correct import paths** regardless of nesting depth
- βœ… **Applies middleware to all generated procedures** through inheritance

**Example Generated Integration:**
```typescript
// In src/generated/orpc/routers/helpers/createRouter.ts
import { permissions } from '../../../../custom-shield';
export const or = os.$context().use(permissions);
```

### Using Custom Shield Files

For advanced use cases, you can provide your own shield file instead of auto-generation:

```prisma
generator orpc {
provider = "prisma-orpc-generator"
output = "./src/generated/orpc"

generateShield = "true"
shieldPath = "../../src/custom-shield" // Dynamically resolved!
}
```

**Supported Path Formats:**
- Relative paths: `"../../src/auth/shield"`
- Project root relative: `"src/auth/shield"`
- Absolute paths: `"/absolute/path/to/shield"`

Your custom shield file should export a `permissions` object:

```typescript
// 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()(({ ctx }) => !!ctx.user);
const isAdmin = rule()(({ ctx }) => ctx.user?.role === 'admin');
const isOwner = rule()(({ ctx, input }) => {
return ctx.user?.id === (input as any)?.userId;
});

export const permissions = shield({
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.

### Generated Shield Rules

The generator creates rules based on your Prisma models:

```typescript
// Built-in rules (generated automatically)
const isAuthenticated = rule()(({ ctx }) => !!ctx.user);

// Example custom rules (user-defined)
const isAdmin = rule()(({ 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({
user: {
list: canReadUser,
findById: canReadUser,
create: canWriteUser,
update: canWriteUser,
delete: canWriteUser,
},
post: {
list: allow,
create: isAuthenticated,
update: isAuthenticated,
},
});
```

### Using Shield in Your Server

Import and use the generated shield:

```typescript
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 */]
});
```

### Context Requirements

Shield rules expect a `Context` with user information:

```typescript
interface Context {
prisma: PrismaClient;
user?: {
id: string;
email?: string;
name?: string;
roles?: string[];
permissions?: string[];
};
}
```

### Customization

Override default rules by modifying the generated `shield.ts`:

```typescript
// Custom rule for post ownership
const isPostOwner = rule()(({ ctx, input }) => {
return ctx.user?.id === (input as any)?.authorId;
});

// Use in shield config
const permissions = shield({
post: {
update: and(isAuthenticated, isPostOwner), // Auth + ownership
delete: or(isAdmin, isPostOwner), // Admin or owner
},
});
```

### Shield Options

| Option | Type | Default | Values | Description |
|---|---|---|---|---|
| generateShield | boolean (string) | "true" | "true", "false" | Enable shield generation |
| shieldPath | string | β€” | β€” | 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" | β€” | 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 |

---


## πŸ§ͺ Examples

Click to expand examples
Run the repo example end-to-end
```bash
npm run example:basic
```

What it does
- Builds the generator
- Generates Prisma artifacts
- Seeds a local DB
- Starts a small server using the generated routers/schemas

Notable files
- Server: [examples/basic/src/server.ts](examples/basic/src/server.ts)
- Seed: [examples/basic/src/seed.ts](examples/basic/src/seed.ts)
- Lib utilities: [examples/basic/src/lib](examples/basic/src/lib)
- Example scripts: [examples/basic/package.json](examples/basic/package.json)

---


## ❓ FAQ / Troubleshooting

Click to expand FAQ and troubleshooting
Prisma version mismatch
- Symptom: generator fails or types not aligned
- Action: ensure Prisma v6+ in dev deps and runtime
- `npm i -D prisma @prisma/client`
- Regenerate: `npx prisma generate`

Node version or ESM issues
- Symptom: runtime errors about module type or syntax
- Action: use Node 18.18.0+, 20.9.0+, or 22.11.0+; align package type with your build, then rebuild `npm run build`

Generated path is unexpected
- Symptom: files not where you expect
- Action: verify your generator output path and config; compare with [examples/basic/src/generated/orpc](examples/basic/src/generated/orpc)

Schema/config validation failures
- Symptom: errors referencing invalid options
- Action: check inputs against [src/config/schema.ts](src/config/schema.ts); fix paths/booleans; re-run generation

Docs not emitted
- Symptom: documentation folder missing
- Action: set `generateDocumentation = "true"` and inspect [src/generators/documentation-generator.ts](src/generators/documentation-generator.ts)

Shield path resolution errors
- Symptom: "Cannot find module" errors for shield imports
- Action: verify `shieldPath` points to correct file; check file exports `permissions` object; ensure path is relative to project root or absolute
- Note: generator now handles dynamic path resolution automatically for common directory structures

---


## πŸ§‘β€πŸ’» Development (Contributing)

Click to expand development guide
Repo quicklinks
- Source: [src/](src)
- Generators: [src/generators/](src/generators)
- Entry point: [src/bin.ts](src/bin.ts)
- Public exports: [src/index.ts](src/index.ts)
- Tests: [tests/](tests)

Local dev loop
```bash
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
```prisma
generator orpc {
provider = "../../lib/bin.js" // relative path to built generator
output = "./src/generated/orpc"
}
```

Testing
```bash
npm test # unit/integration
npm run test:watch # watch
npm run test:e2e # Prisma-backed CRUD
npm run test:coverage # coverage
```

Conventions
- Conventional Commits
- Ensure `npm run build` and `npm run typecheck` pass before PR
- Update [README.md](README.md) if flags/outputs change

---


## πŸ—ΊοΈ Roadmap

- βœ… **Integration with oRPC Shield** - Built-in authorization with dynamic path resolution
- **Schema-based Auth Configuration** - Define authorization rules directly in Prisma schema, JSON, or TypeScript config files
- Plugin hooks for custom emitters
- Config discovery and overrides

---


## πŸ“„ License

- License: MIT β€” see the `LICENSE` file.
- Copyright Β© 2025 Omar Dulaimi.

---


## πŸ™ Acknowledgements

- Prisma and its ecosystem
- oRPC community and patterns
- Zod for runtime validation
- TypeScript tooling
- Vitest and contributors


## πŸ“ Changelog

See [CHANGELOG.md](CHANGELOG.md)

---

Made with ❀️ by [Omar Dulaimi](https://github.com/omar-dulaimi)