skills/bratsos/zodipus/zodipus-setup

zodipus-setup

SKILL.md

Zodipus Setup

Complete guide for installing and configuring Zodipus.

When to Apply

  • User is installing zodipus for the first time
  • User asks about generator configuration options
  • User needs framework-specific setup (Next.js, Express, tRPC)
  • User wants to understand dateFormat, relationDepth, or other options
  • User is setting up a new Prisma project with Zod validation

Installation

# npm
npm install zodipus zod

# pnpm
pnpm add zodipus zod

# yarn
yarn add zodipus zod

Requirements:

  • Node.js 18+
  • Prisma 6.0+
  • Zod 3.25.0+

Basic Configuration

Add to your schema.prisma:

generator client {
  provider = "prisma-client-js"
}

generator zodipus {
  provider = "zodipus"
  output   = "./generated"
}

model User {
  id        String   @id @default(cuid())
  email     String   @unique
  name      String?
  role      Role     @default(USER)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  posts     Post[]
}

model Post {
  id        String   @id @default(cuid())
  title     String
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  String
}

enum Role {
  USER
  ADMIN
}

Generate Schemas

npx prisma generate

This creates:

generated/
├── enums.ts              # RoleSchema
├── models.ts             # UserSchema, PostSchema
├── custom-schemas.ts     # Placeholder for @zodSchema
├── generated-relations.ts
└── generated-index.ts

Configuration Options

Option Type Default Description
provider string Required Must be "zodipus"
output string Required Output directory for generated files
relationDepth string "5" Maximum depth for nested relation extraction
dateFormat string "coerce" DateTime handling: "coerce" or "string"
passthroughEnabled string "false" Allow unknown keys in objects
debug string "false" Enable verbose debug logging
zodImport string "zod" Custom Zod import path

Date Format Options

dateFormat = "coerce" (Default)

Accepts multiple input types, converts to Date:

// All valid inputs:
UserSchema.parse({ createdAt: new Date() });           // Date object
UserSchema.parse({ createdAt: '2024-01-15T10:30:00Z' }); // ISO string
UserSchema.parse({ createdAt: 1705315800000 });        // Timestamp

Use when: Receiving data from various sources (APIs, databases, user input).

dateFormat = "string"

Requires strict ISO 8601 format:

// Only ISO strings accepted:
UserSchema.parse({ createdAt: '2024-01-15T10:30:00.000Z' }); // OK
UserSchema.parse({ createdAt: new Date() }); // Error!

Use when: Building strict APIs, need consistent date format.

Passthrough Mode

passthroughEnabled = "false" (Default)

Unknown keys are stripped:

const data = { id: '1', email: 'a@b.com', unknownField: 'ignored' };
const user = UserSchema.parse(data);
// user = { id: '1', email: 'a@b.com' } - unknownField removed

Use when: Sanitizing input, preventing data leakage.

passthroughEnabled = "true"

Unknown keys are preserved:

const data = { id: '1', email: 'a@b.com', extra: 'kept' };
const user = UserSchema.parse(data);
// user = { id: '1', email: 'a@b.com', extra: 'kept' }

Use when: Transforming data, need to preserve extra fields.

Relation Depth

Controls how deeply nested relations are extracted for the Query Engine:

generator zodipus {
  relationDepth = "10"  # Allow queries 10 levels deep
}

Default: 5 - Sufficient for most apps. Increase if you have deeply nested queries.

Common Configurations

Strict API Server

Best for REST/GraphQL APIs with strict validation:

generator zodipus {
  provider           = "zodipus"
  output             = "./src/generated/zodipus"
  passthroughEnabled = "false"
  dateFormat         = "string"
  relationDepth      = "5"
}

Flexible Data Pipeline

Best for ETL, migrations, or internal tools:

generator zodipus {
  provider           = "zodipus"
  output             = "./generated"
  passthroughEnabled = "true"
  dateFormat         = "coerce"
  relationDepth      = "8"
}

Minimal Setup

Quick start with sensible defaults:

generator zodipus {
  provider = "zodipus"
  output   = "./generated"
}

Framework Integration

Next.js App Router

// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { UserSchema } from '@/generated';
import { prisma } from '@/lib/prisma';

export async function POST(request: NextRequest) {
  const body = await request.json();

  const result = UserSchema.omit({ id: true, createdAt: true, updatedAt: true })
    .safeParse(body);

  if (!result.success) {
    return NextResponse.json({ errors: result.error.flatten() }, { status: 400 });
  }

  const user = await prisma.user.create({ data: result.data });
  return NextResponse.json(UserSchema.parse(user));
}

Express.js

// routes/users.ts
import { Router } from 'express';
import { UserSchema } from '../generated';
import { prisma } from '../lib/prisma';

const router = Router();

router.post('/', async (req, res) => {
  const CreateUserSchema = UserSchema.omit({ id: true, createdAt: true, updatedAt: true });
  const result = CreateUserSchema.safeParse(req.body);

  if (!result.success) {
    return res.status(400).json({ errors: result.error.flatten() });
  }

  const user = await prisma.user.create({ data: result.data });
  res.json(UserSchema.parse(user));
});

export default router;

tRPC

// server/routers/user.ts
import { router, publicProcedure } from '../trpc';
import { UserSchema } from '../../generated';
import { prisma } from '../../lib/prisma';

export const userRouter = router({
  create: publicProcedure
    .input(UserSchema.omit({ id: true, createdAt: true, updatedAt: true }))
    .mutation(async ({ input }) => {
      const user = await prisma.user.create({ data: input });
      return UserSchema.parse(user);
    }),

  getById: publicProcedure
    .input(z.object({ id: z.string() }))
    .query(async ({ input }) => {
      const user = await prisma.user.findUnique({ where: { id: input.id } });
      return user ? UserSchema.parse(user) : null;
    }),
});

Verification

After setup, verify everything works:

// test-setup.ts
import { UserSchema, RoleSchema } from './generated';
import { createRegistry } from 'zodipus/queryEngine';
import { models, modelRelations } from './generated/generated-index';

// Test schema parsing
const user = UserSchema.parse({
  id: 'test-id',
  email: 'test@example.com',
  name: null,
  role: 'USER',
  createdAt: new Date(),
  updatedAt: new Date(),
});
console.log('Schema validation:', user);

// Test Query Engine
const registry = createRegistry({ models, relations: modelRelations });
const userQuery = registry.createQuery('user');
console.log('Query Engine:', userQuery({ select: { id: true } }).query);

Troubleshooting Setup

"Cannot find module './generated'"

Run npx prisma generate after adding the generator.

TypeScript errors after generation

Ensure your tsconfig includes the output directory:

{
  "include": ["src/**/*", "generated/**/*"]
}

ESM/CJS conflicts

Zodipus outputs CommonJS. If using ESM, ensure your bundler handles the conversion.

For detailed options, see references/GENERATOR-OPTIONS.md.

Weekly Installs
3
Repository
bratsos/zodipus
GitHub Stars
1
First Seen
Feb 6, 2026
Installed on
opencode3
gemini-cli3
antigravity3
claude-code3
github-copilot3
codex3