
✨ Enhanced with improved error handling and better TypeScript support
🎯 Zero-config • 🛡️ Type-safe • ⚡ Fast • 🔧 Customizable
Automatically generates type-safe endpoints with Zod validation, middleware support, and optional tRPC Shield integration
If this tool accelerates your development, consider supporting its growth
✨ Your sponsorship drives innovation and keeps this project thriving ✨
🚀 Feature | 📦 Version | 🎯 Benefit |
---|---|---|
Prisma | 6.12.0+ |
🏃♂️ Improved performance & stability |
tRPC | 11.4.3+ |
🛡️ Enhanced type safety & modern APIs |
TypeScript | 5.8+ |
⚡ Cutting-edge language features |
Zod | 4.0+ |
🔍 Advanced validation & error handling |
Testing | Vitest 3 |
🧪 90%+ coverage with modern tooling |
Tooling | ESLint 9 |
🔧 Latest dev experience |
✨ Starting from v2.1.0, full support for the new Prisma Client generator preview feature ✨
This generator now supports both the legacy and new Prisma Client generators:
Generator Type | Provider | Supported Since | Status |
---|---|---|---|
Legacy | prisma-client-js |
v1.0.0+ | ✅ Fully Supported |
Preview | prisma-client |
v2.1.0+ | ✅ Fully Supported |
The following preview features are automatically detected and supported:
Preview Feature | Description | Status |
---|---|---|
queryCompiler |
Improved query compilation performance | ✅ Supported |
driverAdapters |
Enhanced database driver compatibility | ✅ Supported |
metrics |
Query performance metrics collection | ✅ Supported |
Custom features | Any new preview features from Prisma | ✅ Auto-detected |
Legacy Generator (existing projects):
generator client {
provider = "prisma-client-js"
previewFeatures = ["queryCompiler"]
}
generator trpc {
provider = "prisma-trpc-generator"
// ... your config
}
New Generator (Prisma 6.12.0+ projects):
generator client {
provider = "prisma-client"
output = "./generated/client"
previewFeatures = ["queryCompiler", "driverAdapters", "metrics"]
runtime = "nodejs"
moduleFormat = "esm"
}
generator trpc {
provider = "prisma-trpc-generator"
// ... your config
}
Mixed Setup (both generators):
generator clientLegacy {
provider = "prisma-client-js"
}
generator clientNew {
provider = "prisma-client"
output = "./generated/client-new"
previewFeatures = ["queryCompiler", "driverAdapters"]
}
generator trpc {
provider = "prisma-trpc-generator"
// Automatically detects and uses preview features from any client generator
}
📝 Note: Preview features are automatically detected from your Prisma client generator and applied to the generated tRPC routers. No additional configuration needed!
- Node.js 18+
- Prisma 6.12.0+
- tRPC 11.4.3+
- TypeScript 5.8+
# NPM
npm install prisma-trpc-generator
# Yarn
yarn add prisma-trpc-generator
# PNPM
pnpm add prisma-trpc-generator
-
Star this repo 😉
-
Add the generator to your Prisma schema:
generator trpc {
provider = "prisma-trpc-generator"
withZod = true
withMiddleware = false
withShield = false
contextPath = "../src/context"
trpcOptionsPath = "../src/trpcOptions"
}
-
Enable strict mode in
tsconfig.json
(required by Zod):
{
"compilerOptions": {
"strict": true
}
}
- Generate your tRPC routers:
npx prisma generate
For the following schema:
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String
content String?
published Boolean @default(false)
viewCount Int @default(0)
author User? @relation(fields: [authorId], references: [id])
authorId Int?
}
The generator creates:
generated/
├── routers/
│ ├── index.ts # Main app router that combines all model routers
│ ├── helpers/
│ │ └── createRouter.ts # Base router factory with middleware/shield setup
│ ├── User.router.ts # User CRUD operations
│ └── Post.router.ts # Post CRUD operations
└── schemas/ # Zod validation schemas (if withZod: true)
├── objects/ # Input type schemas
├── findManyUser.schema.ts
├── createOneUser.schema.ts
└── index.ts # Barrel exports
Version | Prisma | tRPC | TypeScript | Zod | Node.js | Status |
---|---|---|---|---|---|---|
v2.1.0+ | 6.12.0+ | 11.4.3+ | 5.8+ | 4.0+ | 18+ | ✅ Stable (+ Preview Features) |
v2.0.2 | 6.12.0+ | 11.4.3+ | 5.8+ | 4.0+ | 18+ | ✅ Stable |
v1.4.1 (stable) | 4.8.0+ | 10.7.0+ | 4.9+ | 3.20+ | 16+ | ✅ Stable |
Recommendation: Use the latest stable version for all projects.
Option | Description | Type | Default |
---|---|---|---|
output |
Output directory for generated files | string |
./generated |
withZod |
Generate Zod validation schemas | boolean |
true |
withMiddleware |
Include global middleware support | boolean | string |
true |
withShield |
Generate tRPC Shield permissions | boolean | string |
false |
contextPath |
Path to your tRPC context file | string |
../../../../src/context |
trpcOptionsPath |
Path to tRPC instance options | string |
../../../../src/trpcOptions |
isGenerateSelect |
Enable Select schema generation | boolean |
false |
isGenerateInclude |
Enable Include schema generation | boolean |
false |
showModelNameInProcedure |
Include model name in procedure names | boolean |
true |
generateModelActions |
Specify which CRUD operations to generate | string |
All operations |
generator trpc {
provider = "prisma-trpc-generator"
output = "./src/server/api"
withZod = true
withMiddleware = "../middleware"
withShield = "../permissions"
contextPath = "../context"
trpcOptionsPath = "../trpcOptions"
isGenerateSelect = true
isGenerateInclude = true
showModelNameInProcedure = false
generateModelActions = "findMany,findUnique,create,update,delete"
}
Create a middleware file to run before all procedures:
// src/middleware.ts
import { TRPCError } from '@trpc/server';
import { t } from './trpc';
export const authMiddleware = t.middleware(async ({ ctx, next }) => {
if (!ctx.user) {
throw new TRPCError({ code: 'UNAUTHORIZED' });
}
return next({
ctx: {
...ctx,
user: ctx.user,
},
});
});
export const loggingMiddleware = t.middleware(async ({ path, type, next }) => {
console.log(`tRPC ${type} ${path}`);
return next();
});
Set up permissions using the generated shield:
// src/permissions.ts
import { shield, rule, and, or } from 'trpc-shield';
const isAuthenticated = rule()(async (parent, args, ctx) => {
return !!ctx.user;
});
const isOwner = rule()(async (parent, args, ctx) => {
if (!args.where?.id) return false;
const post = await ctx.prisma.post.findUnique({
where: { id: args.where.id },
select: { authorId: true }
});
return post?.authorId === ctx.user?.id;
});
export const permissions = shield({
query: {
findManyPost: true, // Public
findUniqueUser: isAuthenticated,
},
mutation: {
createOnePost: isAuthenticated,
updateOnePost: and(isAuthenticated, isOwner),
deleteOnePost: and(isAuthenticated, isOwner),
},
});
Configure your tRPC instance with custom options:
// src/trpcOptions.ts
import { ZodError } from 'zod';
import superjson from 'superjson';
export default {
transformer: superjson,
errorFormatter({ shape, error }) {
return {
...shape,
data: {
...shape.data,
zodError:
error.code === 'BAD_REQUEST' && error.cause instanceof ZodError
? error.cause.flatten()
: null,
},
};
},
};
Hide specific models from generation:
/// @@Gen.model(hide: true)
model InternalLog {
id Int @id @default(autoincrement())
message String
createdAt DateTime @default(now())
}
Ensure you have a properly typed context file:
// src/context.ts
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export interface Context {
prisma: PrismaClient;
user?: {
id: string;
email: string;
role: string;
};
}
export const createContext = async ({ req }): Promise<Context> => {
// Add your authentication logic here
const user = await getUserFromRequest(req);
return {
prisma,
user,
};
};
// src/server/routers/posts.ts
import { z } from 'zod';
import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc';
export const postsRouter = createTRPCRouter({
// Public read access
getAll: publicProcedure.query(({ ctx }) => {
return ctx.prisma.post.findMany({
where: { published: true },
include: { author: { select: { name: true } } },
});
}),
// Protected create
create: protectedProcedure
.input(z.object({
title: z.string().min(1),
content: z.string().optional(),
}))
.mutation(({ ctx, input }) => {
return ctx.prisma.post.create({
data: {
...input,
authorId: ctx.user.id,
},
});
}),
// Protected update (owner only)
update: protectedProcedure
.input(z.object({
id: z.number(),
title: z.string().min(1).optional(),
content: z.string().optional(),
}))
.mutation(async ({ ctx, input }) => {
const { id, ...data } = input;
// Verify ownership
const post = await ctx.prisma.post.findFirst({
where: { id, authorId: ctx.user.id },
});
if (!post) {
throw new TRPCError({ code: 'FORBIDDEN' });
}
return ctx.prisma.post.update({
where: { id },
data,
});
}),
});
// src/app/api/trpc/[trpc]/route.ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { appRouter } from '@/server/api/root';
import { createContext } from '@/server/api/context';
const handler = (req: Request) =>
fetchRequestHandler({
endpoint: '/api/trpc',
req,
router: appRouter,
createContext,
});
export { handler as GET, handler as POST };
// src/lib/trpc.ts
import { createTRPCReact } from '@trpc/react-query';
import type { AppRouter } from '@/server/api/root';
export const trpc = createTRPCReact<AppRouter>();
// In your component
const PostList = () => {
const { data: posts, isLoading } = trpc.post.findMany.useQuery();
const createPost = trpc.post.createOne.useMutation();
if (isLoading) return <div>Loading...</div>;
return (
<div>
{posts?.map((post) => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
};
Dependency compatibility errors
- Ensure you're using Node.js 18+
- Update Prisma to 6.12.0+ and tRPC to 11.4.3+
- Check that all peer dependencies are compatible
Migration from v1.x to v2.x
- Backup your project before upgrading
- Update all related dependencies (Prisma, tRPC, Zod)
- Re-run
npx prisma generate
after upgrading - Test thoroughly in development environment
Error: Cannot find module '../context'
- Ensure your
contextPath
is correct relative to the output directory - Check that your context file exports a
Context
type
TypeScript errors in generated routers
- Make sure all dependencies are installed and up to date
- Verify your tRPC context is properly typed
- Ensure
strict: true
is enabled intsconfig.json
Generated routers not updating
- Run
npx prisma generate
after modifying your schema - Check that the generator is properly configured in
schema.prisma
- Clear your build cache and regenerate
Zod validation errors
- Ensure you have Zod 4.0+ installed for compatibility
- Check that your input schemas match your Prisma model types
For projects with many models (50+), consider:
- Using selective generation with model hiding
- Splitting routers into multiple files
- Implementing lazy loading for routers
To optimize build performance:
- Add generated files to
.gitignore
- Use parallel builds where possible
- Consider caching in CI/CD pipelines
Q: Can I customize the generated router validation rules? A: The routers are generated based on your Prisma schema constraints. Modify your Prisma model definitions to change validation rules.
Q: Does this work with Prisma Edge Runtime? A: Yes, the generated routers are compatible with Prisma Edge Runtime.
Q: Can I use this with databases other than the officially supported ones? A: The generator supports all Prisma-compatible databases. Custom databases should work if Prisma supports them.
Q: How do I handle enum validation? A: Enums are automatically converted to Zod enum schemas and included in the generated validation.
Q: Can I exclude certain fields from validation?
A: Use Prisma's @ignore
directive or model-level hiding with @@Gen.model(hide: true)
.
- 🐛 Bug Reports: Create a bug report
- 💡 Feature Requests: Request a feature
- 💬 Discussions: Join the discussion
Contributions are welcome! Here's how you can help:
- Fork and clone the repository
git clone https://github.com/your-username/prisma-trpc-generator.git
cd prisma-trpc-generator
- Install dependencies
npm install
- Run the development build
npm run generate
- Run tests
npm test
We have comprehensive tests covering:
- Unit Tests: Core transformation logic
- Integration Tests: End-to-end router generation
- Multi-Provider Tests: All database providers
- Performance Tests: Large schema handling
Run specific test suites:
npm run test:basic # Basic functionality
npm run test:integration # Integration testing
npm run test:coverage # Coverage reports
npm run test:comprehensive # Full test suite
- Create an issue for bugs or feature requests
- Follow the existing code style (ESLint + Prettier)
- Add tests for new functionality
- Update documentation as needed
- Submit a pull request with a clear description
We use ESLint and Prettier for consistent code formatting:
npm run lint # Check and fix linting issues
npm run format # Format code with Prettier
This project uses semantic versioning and automated releases:
- Patch: Bug fixes and small improvements
- Minor: New features and enhancements
- Major: Breaking changes
This project is licensed under the MIT License - see the LICENSE file for details.
- prisma-zod-generator - Generate Zod schemas from Prisma schema
- prisma-trpc-shield-generator - Generate tRPC Shield permissions from Prisma schema
- tRPC Shield - Permission system for tRPC
- Prisma - Database toolkit and ORM
- tRPC - End-to-end typesafe APIs made easy
- Prisma - Modern database toolkit
- tRPC - End-to-end typesafe APIs
- Zod - TypeScript-first schema validation
- All our contributors