<< All versions
Skill v1.0.0
currentAutomated scan100/100bitovi/ai-enablement-prompts/cross-package-types
──Details
PublishedOctober 24, 2026 at 02:37 PM
Content Hashsha256:6799f5fc81a543a9...
Git SHAdf229b123a1b
──Files
Files (1 file, 4.4 KB)
SKILL.md4.4 KBactive
SKILL.md · 161 lines · 4.4 KB
version: "1.0.0" name: cross-package-types description: Type flow patterns for tRPC + Prisma monorepos. Covers AppRouter type inference across shared, server, and client packages. Use when setting up types, fixing type errors across packages, or understanding the type chain.
Skill: Cross-Package Types (tRPC + Prisma)
Defines how TypeScript types flow through a monorepo with tRPC and Prisma.
Type Flow
Prisma Schema → Prisma Client Types → Zod Schemas → tRPC Routers → Client Type Inference
Package Responsibilities
| Package | Owns | Exports | |
|---|---|---|---|
| shared | Zod schemas, enums, constants | Schemas for both server and client | |
| server | tRPC routers, Prisma client | AppRouter type | |
| client | React components, tRPC hooks | Consumes AppRouter type |
Key Principles
- Prisma is the single source of truth — all types derive from the Prisma schema
- Zod schemas derive from Prisma types — use
.pick(),.omit(),.extend()on base schemas - AppRouter types flow from server to client — never import server code in client
- No circular dependencies — shared → server → client (one direction only)
Shared Package
The shared package has two entry points:
typescript
// package.json{"exports": {"./server": "./src/server/index.ts", // Server-only: Prisma, DB utils".": "./src/index.ts" // Browser-safe: Zod schemas, types, constants}}
Schema Derivation
typescript
// shared/src/schemas/user.tsimport { z } from 'zod';// Base schema matching Prisma modelexport const UserSchema = z.object({id: z.string().uuid(),email: z.string().email(),name: z.string().min(1),role: z.enum(['ADMIN', 'USER', 'VIEWER']),createdAt: z.date(),updatedAt: z.date(),});// Auto-managed fieldsconst PRISMA_AUTO_FIELDS = ['id', 'createdAt', 'updatedAt'] as const;// Input schema (for create)export const CreateUserSchema = UserSchema.omit(Object.fromEntries(PRISMA_AUTO_FIELDS.map(f => [f, true])) as Record<string, true>);// Update schema (partial, without auto fields)export const UpdateUserSchema = CreateUserSchema.partial();// Form schema (client-friendly, no server-only fields)export const UserFormSchema = UserSchema.pick({email: true,name: true,role: true,});export type User = z.infer<typeof UserSchema>;export type CreateUserInput = z.infer<typeof CreateUserSchema>;export type UpdateUserInput = z.infer<typeof UpdateUserSchema>;
Server Package
tRPC Router Pattern
typescript
// server/src/routers/user.tsimport { router, protectedProcedure } from '../trpc';import { CreateUserSchema, UpdateUserSchema } from '@myapp/shared';import { prisma } from '@myapp/shared/server';export const userRouter = router({list: protectedProcedure.query(async () => {return prisma.user.findMany();}),create: protectedProcedure.input(CreateUserSchema).mutation(async ({ input }) => {return prisma.user.create({ data: input });}),update: protectedProcedure.input(z.object({ id: z.string().uuid(), data: UpdateUserSchema })).mutation(async ({ input }) => {return prisma.user.update({ where: { id: input.id }, data: input.data });}),});
AppRouter Export
typescript
// server/src/routers/index.tsimport { router } from '../trpc';import { userRouter } from './user';export const appRouter = router({user: userRouter,});export type AppRouter = typeof appRouter;
Client Package
Type-Safe tRPC Client
typescript
// client/src/utils/trpc.tsimport { createTRPCReact } from '@trpc/react-query';import type { AppRouter } from '@myapp/server';export const trpc = createTRPCReact<AppRouter>();
Usage in Components
typescript
// client/src/components/UserList.tsximport { trpc } from '../utils/trpc';export function UserList() {const { data: users } = trpc.user.list.useQuery();// `users` is fully typed as User[] automatically}
Common Mistakes
- ❌ Importing server code in client (breaks browser bundle)
- ❌ Defining types manually instead of deriving from Prisma/Zod
- ❌ Circular imports between packages
- ❌ Using
anyto silence cross-package type errors - ✅ Use
typeimports:import type { AppRouter } from '@myapp/server' - ✅ Derive all schemas from Prisma base types
- ✅ Use shared package for browser-safe code