## Navbar Links
- Home: https://omar-dulaimi.github.io/prisma-zod-generator/
- Docs: https://omar-dulaimi.github.io/prisma-zod-generator/docs
- Changelog: https://omar-dulaimi.github.io/prisma-zod-generator/docs/changelog
- GitHub: https://github.com/omar-dulaimi/prisma-zod-generator

## All Docs Links
- Prisma Zod Generator: https://omar-dulaimi.github.io/prisma-zod-generator/docs/intro/what-is
- Quick Start: https://omar-dulaimi.github.io/prisma-zod-generator/docs/intro/quick-start
- Core Concepts: https://omar-dulaimi.github.io/prisma-zod-generator/docs/intro/concepts
- Configuration Precedence: https://omar-dulaimi.github.io/prisma-zod-generator/docs/config/precedence
- Generation Modes: https://omar-dulaimi.github.io/prisma-zod-generator/docs/config/modes
- Variants System: https://omar-dulaimi.github.io/prisma-zod-generator/docs/config/variants
- Strict Mode Configuration: https://omar-dulaimi.github.io/prisma-zod-generator/docs/config/strict-mode
- Naming & Presets: https://omar-dulaimi.github.io/prisma-zod-generator/docs/config/naming
- Optional Field Behavior: https://omar-dulaimi.github.io/prisma-zod-generator/docs/config/optional-fields
- DateTime Strategy: https://omar-dulaimi.github.io/prisma-zod-generator/docs/config/datetime-strategy
- JSON Schema Compatibility: https://omar-dulaimi.github.io/prisma-zod-generator/docs/config/json-schema-compatibility
- Dual Schema Exports: https://omar-dulaimi.github.io/prisma-zod-generator/docs/config/dual-exports
- Model / Operation / Field Filtering: https://omar-dulaimi.github.io/prisma-zod-generator/docs/config/filtering
- Emission Controls: https://omar-dulaimi.github.io/prisma-zod-generator/docs/config/emission-controls
- File Layout & Single File Mode: https://omar-dulaimi.github.io/prisma-zod-generator/docs/config/file-layout
- JSON Schema IntelliSense: https://omar-dulaimi.github.io/prisma-zod-generator/docs/config/schema-json
- Object & CRUD Generation: https://omar-dulaimi.github.io/prisma-zod-generator/docs/pipeline/objects-crud
- Pure Model Schemas: https://omar-dulaimi.github.io/prisma-zod-generator/docs/pipeline/pure-models
- Single File Mode: https://omar-dulaimi.github.io/prisma-zod-generator/docs/pipeline/single-file
- Special Type Mapping: https://omar-dulaimi.github.io/prisma-zod-generator/docs/pipeline/special-types
- @zod Comment Annotations: https://omar-dulaimi.github.io/prisma-zod-generator/docs/pipeline/zod-comments
- Minimal CRUD: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/minimal-crud
- Models Only: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/models-only
- Pure Models Lean: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/pure-models-lean
- CRUD Only: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/crud-only
- Result Variant Only: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/result-only
- Input Variant Only: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/input-only
- Zod import targets: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/zod-import-targets
- tRPC Optimized: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/trpc-optimized
- Single File Bundle: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/single-file
- Granular Per Model: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/granular-per-model
- Hide Sensitive Fields: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/hide-fields
- Flexible API Validation: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/flexible-api-validation
- Circular Dependency Exclusion: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/circular-dependency-exclusion
- Optional Field Control: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/optional-field-control
- Custom Safety Configuration: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/safety-custom-configuration
- Force Using Dangerous Paths: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/safety-force-dangerous-path
- Project Migration Safety Guide: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/safety-project-migration
- Disable Safety System Completely: https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/safety-disable-completely
- Safety System: https://omar-dulaimi.github.io/prisma-zod-generator/docs/reference/safety-system
- Bytes & JSON Details: https://omar-dulaimi.github.io/prisma-zod-generator/docs/reference/bytes-json
- WhereUniqueInput Semantics: https://omar-dulaimi.github.io/prisma-zod-generator/docs/reference/where-unique-input
- Naming Preset Map: https://omar-dulaimi.github.io/prisma-zod-generator/docs/reference/naming-preset-map
- Logging & Debug Output: https://omar-dulaimi.github.io/prisma-zod-generator/docs/reference/logging-debug
- FAQ: https://omar-dulaimi.github.io/prisma-zod-generator/docs/reference/faq
- Troubleshooting: https://omar-dulaimi.github.io/prisma-zod-generator/docs/reference/troubleshooting
- PZG Pro CLI & API Reference: https://omar-dulaimi.github.io/prisma-zod-generator/docs/reference/pro-cli
- Integration Guides Overview: https://omar-dulaimi.github.io/prisma-zod-generator/docs/integrations/overview
- Pro Features Overview: https://omar-dulaimi.github.io/prisma-zod-generator/docs/features/overview
- Policies & Redaction: https://omar-dulaimi.github.io/prisma-zod-generator/docs/features/policies
- Form UX Pack: https://omar-dulaimi.github.io/prisma-zod-generator/docs/features/forms
- SDK Publisher: https://omar-dulaimi.github.io/prisma-zod-generator/docs/features/sdk
- API Docs Pack: https://omar-dulaimi.github.io/prisma-zod-generator/docs/features/api-docs
- PostgreSQL RLS: https://omar-dulaimi.github.io/prisma-zod-generator/docs/features/postgres-rls
- Multi-Tenant Kit: https://omar-dulaimi.github.io/prisma-zod-generator/docs/features/multi-tenant
- Performance Pack: https://omar-dulaimi.github.io/prisma-zod-generator/docs/features/performance
- Data Factories: https://omar-dulaimi.github.io/prisma-zod-generator/docs/features/factories
- Drift Guard: https://omar-dulaimi.github.io/prisma-zod-generator/docs/features/guard
- Contract Testing Pack: https://omar-dulaimi.github.io/prisma-zod-generator/docs/features/contracts
- Server Actions Pack: https://omar-dulaimi.github.io/prisma-zod-generator/docs/features/server-actions
- Usage Patterns: https://omar-dulaimi.github.io/prisma-zod-generator/docs/usage-patterns
- Performance & Build Tips: https://omar-dulaimi.github.io/prisma-zod-generator/docs/performance
- Upgrade Guide: https://omar-dulaimi.github.io/prisma-zod-generator/docs/upgrade-guide
- Upgrade from Free to Pro: https://omar-dulaimi.github.io/prisma-zod-generator/docs/upgrade/pro-migration
- Contributing: https://omar-dulaimi.github.io/prisma-zod-generator/docs/contributing
- Changelog: https://omar-dulaimi.github.io/prisma-zod-generator/docs/changelog
- JSON-friendly DateTime (Split Strategy Default): https://omar-dulaimi.github.io/prisma-zod-generator/docs/recipes/json-friendly-datetime

# Prisma Zod Generator

> Prisma → Zod in one generate. Ship validated, typed data everywhere.

Last updated: 2025-11-21 • Version: 1.32.2

## Quick start

- Install: `npm i -D prisma-zod-generator`
- In `schema.prisma`:
  ```prisma
  generator zod { provider = "prisma-zod-generator" }
  ```
- Generate: `npx prisma generate`
- Import:
  ```ts
  import { UserSchema } from "./prisma/generated/schemas";
  ```

## Highlights

- Zero‑boilerplate Zod schemas from Prisma models
- Multiple variants: input, result, pure
- Fast minimal mode & selective filtering
- Strict types • ESM/CJS friendly • TypeScript‑first

## Links

- Docs: https://omar-dulaimi.github.io/prisma-zod-generator/
- NPM: https://www.npmjs.com/package/prisma-zod-generator
- Repo: https://github.com/omar-dulaimi/prisma-zod-generator
- Issues: https://github.com/omar-dulaimi/prisma-zod-generator/issues
- Sponsor: https://github.com/sponsors/omar-dulaimi

## Configuration

Add to your Prisma schema:
```prisma
generator zod {
  provider = "prisma-zod-generator"
  // optional: output, disabledModels, modelNameStrategy, etc.
}
```
Run `npx prisma generate` to emit schemas.

## Recipes

- See `recipes/` in the repo and docs site.

## Notes

- Requires Node.js 18+
- Works with Prisma's `prisma generate` lifecycle

# DateTime Strategy

# DateTime Strategy

Configure how Prisma `DateTime` fields are validated in your generated Zod schemas.

## Overview

The generator supports two complementary controls for DateTime behavior:

- dateTimeSplitStrategy (boolean, default: true) controls the default behavior when no explicit dateTimeStrategy is set.
- dateTimeStrategy ('date' | 'coerce' | 'isoString') forces a specific mapping across all variants.

When dateTimeSplitStrategy is true and dateTimeStrategy is NOT set:

- Input schemas default to z.coerce.date() (JSON-friendly — accepts ISO strings and coerces to Date)
- Pure model and result schemas default to z.date()

When dateTimeStrategy is set, it takes precedence and applies to all variants.

## Split Strategy (Default)

With split enabled (default):

- Inputs: z.coerce.date() (accepts ISO strings)
- Pure/Results: z.date()
  This provides a JSON-first default for APIs while keeping strict Date objects in read models.

Disable split by setting "dateTimeSplitStrategy": false to revert to a single global default (see strategies below).

## Available Strategies

### `date` (Default)

Generates strict `z.date()` validation that only accepts JavaScript Date objects.

```jsonc
{
  "dateTimeStrategy": "date"
}
```

**Generated schema:**

```typescript
// For a createdAt: DateTime field
createdAt: z.date()
```

**Usage:**

```typescript
// ✅ Valid
const data = { createdAt: new Date() };

// ❌ Invalid - string not accepted
const data = { createdAt: "2023-01-01T00:00:00Z" };
```

### `coerce`

Generates `z.coerce.date()` validation that automatically converts valid date strings to Date objects.

```jsonc
{
  "dateTimeStrategy": "coerce"
}
```

**Generated schema:**

```typescript
// For a createdAt: DateTime field
createdAt: z.coerce.date()
```

**Usage:**

```typescript
// ✅ Both valid - string automatically converted
const data1 = { createdAt: new Date() };
const data2 = { createdAt: "2023-01-01T00:00:00Z" };
```

### `isoString`

Generates string validation with ISO 8601 regex pattern and transform to Date object.

```jsonc
{
  "dateTimeStrategy": "isoString"
}
```

**Generated schema:**

```typescript
// For a createdAt: DateTime field
createdAt: z.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/).transform(v => new Date(v))
```

**Usage:**

```typescript
// ✅ Valid - ISO string accepted and transformed
const data = { createdAt: "2023-01-01T00:00:00.000Z" };

// ❌ Invalid - must be valid ISO string
const data = { createdAt: "invalid-date" };
```

## Configuration Examples

### Schema Generator Block

```prisma
generator zod {
  provider = "prisma-zod-generator"
  output   = "./generated/zod"
  config   = "./zod-generator.config.json"
}
```

### JSON Configuration File

```jsonc
// zod-generator.config.json
{
  "mode": "custom",
  "dateTimeStrategy": "coerce",
  "pureModels": true,
  "variants": {
    "pure": { "enabled": true, "suffix": ".model" },
    "input": { "enabled": true, "suffix": ".input" },
    "result": { "enabled": true, "suffix": ".result" }
  }
}
```

### Direct Generator Options

```prisma
generator zod {
  provider         = "prisma-zod-generator"
  output           = "./generated/zod"
  dateTimeStrategy = "isoString"
}
```

## Use Cases

### `date` Strategy

- **Best for:** Type-safe applications where you work with Date objects
- **API validation:** When your frontend sends Date objects directly
- **Internal validation:** Component props, function parameters

### `coerce` Strategy

- **Best for:** API endpoints accepting flexible date input
- **Form handling:** User input from date pickers or text fields
- **Data migration:** Converting between different date formats

### `isoString` Strategy

- **Best for:** Strict API contracts requiring ISO 8601 format
- **Database consistency:** Ensuring standardized date string format
- **Logging/serialization:** When you need predictable string representation

## Impact on Generated Schemas

The `dateTimeStrategy` affects all DateTime fields across:

- **Pure models** (when `pureModels: true`)
- **Input variants** (create, update operations)
- **Result variants** (query responses)
- **CRUD operation schemas**

### Example Model

```prisma
model Post {
  id        String   @id @default(cuid())
  title     String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
```

### Generated Output Comparison

```typescript
// dateTimeStrategy: "date"
export const PostModel = z.object({
  id: z.string(),
  title: z.string(),
  createdAt: z.date(),
  updatedAt: z.date(),
});

// dateTimeStrategy: "coerce"  
export const PostModel = z.object({
  id: z.string(),
  title: z.string(),
  createdAt: z.coerce.date(),
  updatedAt: z.coerce.date(),
});

// dateTimeStrategy: "isoString"
export const PostModel = z.object({
  id: z.string(),
  title: z.string(),
  createdAt: z.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/).transform(v => new Date(v)),
  updatedAt: z.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/).transform(v => new Date(v)),
});
```

## Migration Guide

When changing `dateTimeStrategy`, regenerate your schemas and update consuming code:

### From `date` to `coerce`

- No breaking changes for existing Date object usage
- New: string inputs now accepted and converted

### From `date` to `isoString`

- **Breaking:** Only ISO strings accepted, Date objects rejected
- Update client code to send ISO string format

### From `coerce` to `isoString`

- **Breaking:** More restrictive validation
- Non-ISO date strings will be rejected

## Related Configuration

- [`pureModels`](./modes.md): When enabled, affects pure model DateTime fields
- [`variants`](./variants.md): Controls which schema variants include DateTime strategy
- [`optionalFieldBehavior`](./optional-fields.md): May affect nullable DateTime fields

## Troubleshooting

### Date Validation Errors

```typescript
// If using "date" strategy but sending strings
const result = PostModel.safeParse({
  title: "Hello",
  createdAt: "2023-01-01" // ❌ String not accepted
});

// Solution: Convert to Date or use "coerce" strategy
const result = PostModel.safeParse({
  title: "Hello", 
  createdAt: new Date("2023-01-01") // ✅ Date object
});
```

### ISO String Format Issues

```typescript
// If using "isoString" strategy
const result = PostModel.safeParse({
  title: "Hello",
  createdAt: "2023-1-1" // ❌ Invalid ISO format
});

// Solution: Use proper ISO 8601 format
const result = PostModel.safeParse({
  title: "Hello",
  createdAt: "2023-01-01T00:00:00.000Z" // ✅ Valid ISO
});
```

# Dual Schema Exports

Type-safe + method-friendly exports for CRUD argument schemas.

## Rationale

Traditional choice: bind `z.ZodType<Prisma.X>` (great inference, limited chaining) vs plain Zod (full chaining, looser typing). Generator emits both.

## What You Get

```ts
export const PostFindManySchema: z.ZodType<Prisma.PostFindManyArgs> = base;
export const PostFindManyZodSchema = base;
```

Typed one locks inference to Prisma.\*; Zod one supports all refinements/extensions.

## Enabling / Disabling

Generator block flags (not JSON config):

```prisma
generator zod {
  provider           = "prisma-zod-generator"
  exportTypedSchemas = true   // default
  exportZodSchemas   = true   // default
  typedSchemaSuffix  = "Schema"    // default
  zodSchemaSuffix    = "ZodSchema" // default
}
```

Disable one side to shrink surface:

```prisma
exportTypedSchemas = false
```

## Suffix Customization

Change names to fit convention:

```prisma
typedSchemaSuffix = "Args"
zodSchemaSuffix   = "Validator"
```

Produces `PostFindManyArgs` and `PostFindManyValidator`.

## Single File Mode

Both exports inlined; tree-shakers can drop unused variant if imported selectively.

## When to Prefer One

- Library boundary: use typed version for stable contract.
- App code needing transformation: use Zod version then `.parse`.

## Interactions

- No effect on pure model schemas (they are single export each).
- Result schemas follow same pattern.

## Troubleshooting

If you only see one export: verify flags or earlier README examples; ensure no custom fork removed dual export logic.

# Emission Controls

Flags under `emit` can disable whole categories early:

- `enums`
- `objects` (input object schemas)
- `crud` (operation argument/result grouping)
- `pureModels`
- `variants` (wrapper / variant sets)
- `results` (result schemas)

Skipping enums while generating objects or CRUD may break references → warning emitted.

Heuristic shortcuts (`pureModelsOnlyMode`, `pureVariantOnlyMode`) suppress objects / CRUD regardless of their flags.

See also: [Dual Schema Exports](./dual-exports.md) for typed vs method-friendly CRUD/result schema pairs.

# File Layout & Single File Mode

Options:

- `useMultipleFiles` (default true)
- `singleFileName` (default `schemas.ts`)
- `placeSingleFileAtRoot` (default true) – root of output vs `schemas/` subdir
- `placeArrayVariantsAtRoot` (only for array variants)

Single-file mode:

1. Aggregates generated content (initSingleFile)
2. Writes final bundle (flushSingleFile)
3. Cleans sibling files in target directory
4. Disables variant emission path

Layout conflicts between generator block & JSON config are surfaced (generator block wins).

# Model / Operation / Field Filtering

Model enable check: `isModelEnabled` (minimal mode defaults to disabled unless configured).

Operation filtering: `isOperationEnabled` with alias mapping (createOne→create, etc.). Minimal mode reduces allowed ops unless overridden.

## Schema-Level Filtering

In minimal mode, entire schema types are filtered out to reduce complexity:

**Blocked in minimal mode:**

- `*CreateInput` schemas (use `*UncheckedCreateInput` instead)
- Nested relation inputs (`*CreateNestedInput`, `*UpdateNestedInput`)
- Complex relation patterns (`*CreateWithoutInput`, `*CreateOrConnectWithoutInput`)
- Aggregation inputs (`*AggregateInput`, etc.)
- Select/Include helper schemas

**Always allowed:**

- `*UncheckedCreateInput` (simple foreign key-based creation)
- `*UpdateInput` and `*UncheckedUpdateInput` (update flexibility)
- `*WhereInput` and `*WhereUniqueInput` (query filtering)
- `*OrderByWithRelationInput` (sorting)

## Field-Level Filtering

Field filtering precedence (stop at first include win):

1. `model.fields.include`
2. Model variant `excludeFields`
3. Legacy `model.fields.exclude`
4. `globalExclusions[variant]`
5. Global array legacy excludes

Wildcard patterns supported: `field*`, `*field`, `*middle*`.

WhereUniqueInput & strict base create inputs bypass variant exclusions to preserve shape fidelity.

Excluded relation fields cause foreign key scalar preservation for create inputs (maintain referential integrity constraints).

## Optional Early Validation for WhereUniqueInput

By default, `WhereUniqueInput` schemas include only unique selector fields (single-field uniques and named composite unique objects). Top-level keys are optional to match Prisma, and completeness for composite selectors is enforced by the nested composite object schemas themselves.

If you want early failure when no selector is present (e.g., rejecting `{}` before reaching Prisma), enable this opt-in flag in your JSON config:

```jsonc
// zod-generator.config.json
{
  "validateWhereUniqueAtLeastOne": true
}
```

This adds a minimal superRefine that checks only the presence of at least one top-level selector. It does not enforce “exactly one” (Prisma will still validate that at runtime) and does not attempt to peek into nested composite fields (those are already required by their own schemas).

# JSON Schema Compatibility

# JSON Schema Compatibility

Generate schemas that are fully compatible with [Zod's JSON Schema conversion](https://zod.dev/json-schema) (`z.toJSONSchema()`), enabling seamless integration with OpenAPI documentation tools, API validators, and JSON Schema-based systems.

## Overview

By default, Prisma Zod Generator creates schemas using Zod types that cannot be represented in JSON Schema:

- `z.date()` for DateTime fields
- `z.bigint()` for BigInt fields
- `z.instanceof(Uint8Array)` for Bytes fields
- `z.unknown()` for relations and JSON fields

When `jsonSchemaCompatible` is enabled, these types are automatically converted to JSON Schema-compatible alternatives while preserving validation logic.

## Configuration

### Basic Setup

```json
{
  "jsonSchemaCompatible": true
}
```

### Advanced Options

```json
{
  "jsonSchemaCompatible": true,
  "jsonSchemaOptions": {
    "dateTimeFormat": "isoString",
    "bigIntFormat": "string", 
    "bytesFormat": "base64String",
    "conversionOptions": {
      "unrepresentable": "any",
      "cycles": "throw",
      "reused": "inline"
    }
  }
}
```

## Type Conversions

### DateTime Fields

**Default Behavior:**

```typescript
// Generated schema (not JSON Schema compatible)
z.date()
```

**JSON Schema Compatible:**

```typescript
// ISO String format (default)
z.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/, "Invalid ISO datetime")

// ISO Date format
z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Invalid ISO date")
```

**Configuration:**

- `dateTimeFormat: "isoString"` - Full ISO 8601 datetime (default)
- `dateTimeFormat: "isoDate"` - ISO date only (YYYY-MM-DD)

### BigInt Fields

**Default Behavior:**

```typescript
// Generated schema (not JSON Schema compatible)
z.bigint()
```

**JSON Schema Compatible:**

```typescript
// String format (default)
z.string().regex(/^\d+$/, "Invalid bigint string")

// Number format (may lose precision for very large numbers)
z.number().int()
```

**Configuration:**

- `bigIntFormat: "string"` - Represents as string (default, preserves precision)
- `bigIntFormat: "number"` - Represents as number (potential precision loss)

### Bytes Fields

**Default Behavior:**

```typescript
// Generated schema (not JSON Schema compatible)
z.instanceof(Uint8Array)
```

**JSON Schema Compatible:**

```typescript
// Base64 string format (default)
z.string().regex(/^[A-Za-z0-9+/]*={0,2}$/, "Invalid base64 string")

// Hexadecimal string format
z.string().regex(/^[0-9a-fA-F]*$/, "Invalid hex string")
```

**Configuration:**

- `bytesFormat: "base64String"` - Base64 encoded string (default)
- `bytesFormat: "hexString"` - Hexadecimal encoded string

### Relations and JSON Fields

**Default Behavior:**

```typescript
// Generated schema (not JSON Schema compatible)
z.unknown()
```

**JSON Schema Compatible:**

```typescript
// Allows any value (JSON Schema compatible)
z.any()
```

## Usage Examples

### Basic Usage

```typescript
import { z } from 'zod';
import { UserModelSchema } from './generated/schemas/variants/pure/User.pure';

// Convert to JSON Schema
const jsonSchema = z.toJSONSchema(UserModelSchema);

// Use with OpenAPI
const openApiSpec = {
  components: {
    schemas: {
      User: jsonSchema
    }
  }
};
```

### OpenAPI Integration

```typescript
import { z } from 'zod';
import { 
  UserCreateInputSchema,
  UserUpdateInputSchema,
  UserModelSchema 
} from './generated/schemas';

// Generate OpenAPI schemas
const schemas = {
  UserCreateRequest: z.toJSONSchema(UserCreateInputSchema),
  UserUpdateRequest: z.toJSONSchema(UserUpdateInputSchema),
  UserResponse: z.toJSONSchema(UserModelSchema)
};

// Use in OpenAPI spec
const openApiSpec = {
  openapi: '3.0.0',
  components: { schemas },
  paths: {
    '/users': {
      post: {
        requestBody: {
          content: {
            'application/json': {
              schema: { $ref: '#/components/schemas/UserCreateRequest' }
            }
          }
        },
        responses: {
          '201': {
            content: {
              'application/json': {
                schema: { $ref: '#/components/schemas/UserResponse' }
              }
            }
          }
        }
      }
    }
  }
};
```

### API Documentation Generation

```typescript
import { z } from 'zod';

// Import any generated schema
import { PostModelSchema } from './generated/schemas/variants/pure/Post.pure';

// Generate documentation-friendly JSON Schema
const postSchema = z.toJSONSchema(PostModelSchema, {
  target: 'openApi3',
  unrepresentable: 'any'
});

// Use with documentation generators like @apidevtools/swagger-jsdoc
const swaggerSpec = {
  openapi: '3.0.0',
  info: { title: 'API', version: '1.0.0' },
  components: {
    schemas: {
      Post: postSchema
    }
  }
};
```

## Schema Variants Support

JSON Schema compatibility works across all schema variants:

### Pure Models

```typescript
import { UserModelSchema } from './generated/schemas/variants/pure/User.pure';
const userJsonSchema = z.toJSONSchema(UserModelSchema);
```

### Input Schemas

```typescript
import { UserCreateInputSchema } from './generated/schemas/variants/input/User.input';
const createUserJsonSchema = z.toJSONSchema(UserCreateInputSchema);
```

### Result Schemas

```typescript
import { UserFindManyResultSchema } from './generated/schemas/variants/result/User.result';
const findManyJsonSchema = z.toJSONSchema(UserFindManyResultSchema);
```

## Conversion Options

Configure how `z.toJSONSchema()` handles edge cases:

```json
{
  "jsonSchemaCompatible": true,
  "jsonSchemaOptions": {
    "conversionOptions": {
      "unrepresentable": "any",
      "cycles": "throw", 
      "reused": "inline"
    }
  }
}
```

### Options Reference

- **`unrepresentable`**: How to handle unrepresentable types
  - `"any"` - Convert to `any` type (default)
  - `"throw"` - Throw error on unrepresentable types

- **`cycles`**: How to handle circular references
  - `"throw"` - Throw error on cycles (default)
  - `"ref"` - Use JSON Schema references

- **`reused`**: How to handle reused schemas
  - `"inline"` - Inline repeated schemas (default)
  - `"ref"` - Use JSON Schema references

## Validation Behavior

JSON Schema compatible schemas maintain validation while changing representation:

```typescript
// DateTime validation
const dateString = "2023-12-25T10:30:00.000Z";
const result = UserModelSchema.parse({ createdAt: dateString });
// ✅ Validates against ISO datetime regex

// BigInt validation  
const bigIntString = "12345678901234567890";
const result2 = PostModelSchema.parse({ likes: bigIntString });
// ✅ Validates against numeric string regex

// Bytes validation
const base64String = "SGVsbG8gV29ybGQ=";
const result3 = PostModelSchema.parse({ data: base64String });
// ✅ Validates against base64 regex
```

## Performance Considerations

- **Regex Validation**: JSON Schema compatible mode uses regex validation which may be slightly slower than native type checking
- **String Conversion**: Applications need to handle string-to-type conversion in business logic
- **Memory Usage**: Regex patterns add minimal memory overhead

## Migration Guide

### From Regular Schemas

1. **Enable compatibility mode:**

```json
{
  "jsonSchemaCompatible": true
}
```

2. **Update application code:**

```typescript
// Before: Date objects
const user = { createdAt: new Date() };

// After: ISO strings  
const user = { createdAt: new Date().toISOString() };
```

3. **Update validation:**

```typescript
// Before: Direct usage
const result = UserModelSchema.parse(userData);

// After: Convert types as needed
const result = UserModelSchema.parse({
  ...userData,
  createdAt: userData.createdAt.toISOString(),
  likes: userData.likes.toString()
});
```

## Troubleshooting

### Common Issues

**Error: "Cannot be represented in JSON Schema"**

```
Solution: Ensure jsonSchemaCompatible is enabled in configuration
```

**Validation failing with valid data**

```typescript
// Check that data matches expected string formats
const validDateTime = "2023-12-25T10:30:00.000Z"; // ✅
const invalidDateTime = "Dec 25, 2023";           // ❌
```

**Precision loss with BigInt**

```typescript
// Use string format for large numbers
{
  "jsonSchemaOptions": {
    "bigIntFormat": "string"  // Preserves precision
  }
}
```

### Debugging

Enable debug logging to see conversion details:

```bash
DEBUG_PRISMA_ZOD=1 prisma generate
```

## Related

- [DateTime Strategy](./datetime-strategy) - Configure DateTime handling
- [Variants](./variants) - Schema variant configuration
- [Zod JSON Schema Documentation](https://zod.dev/json-schema) - Official Zod JSON Schema docs

# Generation Modes

| Mode    | Models default                        | Variants default                        | Operations                  | Notes                                                 |
| ------- | ------------------------------------- | --------------------------------------- | --------------------------- | ----------------------------------------------------- |
| full    | all enabled                           | all enabled                             | all Prisma ops              | Richest output                                        |
| minimal | disabled unless explicitly configured | input & pure enabled (result often off) | Restricted core CRUD + find | Prunes complex nested inputs, disables select/include |
| custom  | all enabled unless disabled           | respect `variants.*.enabled`            | all unless filtered         | Explicit control                                      |

Minimal mode specifics:

- Forces `select/include` disabled even if flags set.
- Applies `MINIMAL_OPERATIONS` (or `minimalOperations` override) for unspecified models.
- Skips many heavy nested input object schemas (allow-list basics).
- **Create operations use `UncheckedCreateInput` only**: Blocks regular `*CreateInput` schemas that require complex nested relations, favoring simple foreign key-based `*UncheckedCreateInput` schemas.
- **Update operations support both variants**: Allows both `*UpdateInput` and `*UncheckedUpdateInput` for flexibility.

## Emission Heuristics

| Condition                                                              | Effect                                                            |
| ---------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `pureModels=true` AND all `variants.*.enabled=false` AND `mode=custom` | Pure-models-only (emit only pure model schemas)                   |
| `pureModels=true` AND only `variants.pure.enabled=true`                | Pure-variant-only (skip CRUD/input/result schemas)                |
| `emit.results=false`                                                   | Internally sets `variants.result.enabled=false` before generation |
| `useMultipleFiles=false`                                               | Single-file bundle; directory cleanup after flush                 |
| `mode=minimal`                                                         | Suppresses select/include + prunes deep input objects             |

Explicit `emit.*` booleans, when provided, override heuristics for that category (except minimal’s enforced suppressions).

# Naming & Presets

## Pure Model Naming

Pure model naming resolved by `resolvePureModelNaming`:

### Presets:

- `default`: `{Model}.schema.ts`, export `{Model}Schema` / type `{Model}Type`.
- `zod-prisma`: same as default + legacy aliases.
- `zod-prisma-types`: file `{Model}.schema.ts`, export `{Model}` (no suffixes), legacy aliases.
- `legacy-model-suffix`: `{Model}.model.ts`, export `{Model}Model`.

### Overrides via `naming.pureModel`:

- `filePattern` (`{Model}.schema.ts`, supports tokens `{Model}{SchemaSuffix}` etc.)
- `schemaSuffix`, `typeSuffix`, `exportNamePattern`, `legacyAliases`.

Relation import rewriting adapts when using `.model` pattern.

## Schema Naming (CRUD Operations)

Schema naming resolved by `resolveSchemaNaming`:

### Default Patterns:

- `filePattern`: `{operation}{Model}.schema.ts`
- `exportNamePattern`: `{Model}{Operation}Schema`

### Examples:

- `findManyUser.schema.ts` with export `UserFindManySchema`
- `createOnePost.schema.ts` with export `PostCreateOneSchema`

### Overrides via `naming.schema`:

```json
{
  "naming": {
    "schema": {
      "filePattern": "{kebab}-{operation}-{model}.schema.ts",
      "exportNamePattern": "{Model}{Operation}ValidationSchema"
    }
  }
}
```

### ⚠️ Important Pattern Requirements

**Operation Token Required**: Your `filePattern` MUST include an operation token (`{operation}` or `{Operation}`) to avoid file collisions. Without it, all CRUD operations for the same model will overwrite each other, resulting in only the last operation being generated.

**Examples**:

- ✅ `{kebab}-{operation}-schema.ts` → `user-findMany-schema.ts`, `user-createOne-schema.ts`
- ✅ `{operation}{Model}.schema.ts` → `findManyUser.schema.ts`, `createOneUser.schema.ts`
- ❌ `{kebab}-schema.ts` → `user-schema.ts` (all operations overwrite each other!)

**Collision Detection**: The generator will detect filename collisions and throw an error during generation. Always include `{operation}` or `{Operation}` in your pattern.

### Available Tokens:

- `{Model}`: PascalCase model name (e.g., `User`, `BlogPost`)
- `{model}`: camelCase model name (e.g., `user`, `blogPost`)
- `{kebab}`: kebab-case model name (e.g., `user`, `blog-post`)
- `{Operation}`: PascalCase operation (e.g., `FindMany`, `CreateOne`)
- `{operation}`: camelCase operation (e.g., `findMany`, `createOne`)

## Input Object Naming

Input object naming resolved by `resolveInputNaming`:

### Default Patterns:

- `filePattern`: `{InputType}.schema.ts`
- `exportNamePattern`: `{Model}{InputType}ObjectSchema`

### Examples:

- `UserWhereInput.schema.ts` with export `UserWhereInputObjectSchema`
- `PostCreateInput.schema.ts` with export `PostCreateInputObjectSchema`

### Overrides via `naming.input`:

```json
{
  "naming": {
    "input": {
      "filePattern": "{kebab}-{InputType}-input.ts",
      "exportNamePattern": "{Model}{InputType}"
    }
  }
}
```

### Available Tokens:

- `{Model}`: PascalCase model name extracted from input type
- `{model}`: camelCase model name
- `{kebab}`: kebab-case model name (e.g., `user`, `blog-post`)
- `{InputType}`: Full input type name (e.g., `UserWhereInput`, `PostCreateInput`)

### ⚠️ Important Pattern Requirements

**File Pattern Must Include Unique Identifiers**: Your `filePattern` must include tokens that make each input type unique. Without proper uniqueness, multiple input types for the same model will generate identical filenames and overwrite each other.

**Recommended Patterns**:

- ✅ `{kebab}-{InputType}-input.ts` → `book-BookCreateInput-input.ts`
- ✅ `{InputType}.schema.ts` → `BookCreateInput.schema.ts`
- ✅ `inputs/{Model}/{InputType}.ts` → `inputs/Book/BookCreateInput.ts`
- ❌ `{kebab}-input.ts` → `book-input.ts` (all Book inputs collide!)

**Pattern Collision Detection**: The generator will detect filename collisions and report errors during generation. If you see errors about duplicate filenames, ensure your pattern includes sufficient tokens to uniquely identify each input type.

**Note**: When your pattern includes a model token (`{Model}` or `{model}`) together with `{InputType}`, duplicate model prefixes are automatically stripped for both export names and file names to avoid results like `UserUserWhereInput*`.

## Enum Naming

Enum naming resolved by `resolveEnumNaming`:

### Default Patterns:

- `filePattern`: `{Enum}.schema.ts`
- `exportNamePattern`: `{Enum}Schema`

### Examples:

- `Role.schema.ts` with export `RoleSchema`
- `UserStatus.schema.ts` with export `UserStatusSchema`

### Overrides via `naming.enum`:

```json
{
  "naming": {
    "enum": {
      "filePattern": "{Enum}Validator.schema.ts",
      "exportNamePattern": "{Enum}ValidatorSchema"
    }
  }
}
```

### Available Tokens:

- `{Enum}`: PascalCase enum name (e.g., `Role`, `UserStatus`)
- `{enum}`: camelCase enum name (e.g., `role`, `userStatus`)
- `{camel}`: camelCase alias (same as `{enum}` for enums)

## Complete Configuration Example

```json
{
  "naming": {
    "preset": "default",
    "pureModel": {
      "filePattern": "{Model}.model.ts",
      "exportNamePattern": "{Model}Model"
    },
    "schema": {
      "filePattern": "{operation}-{kebab}.schema.ts",
      "exportNamePattern": "{Model}{Operation}ValidationSchema"
    },
    "input": {
      "filePattern": "inputs/{InputType}.schema.ts",
      "exportNamePattern": "{InputType}Schema"
    },
    "enum": {
      "filePattern": "enums/{Enum}.enum.ts",
      "exportNamePattern": "{Enum}EnumSchema"
    }
  }
}
```

This would generate:

- Pure models: `User.model.ts` → `UserModel`
- Schemas: `findMany-user.schema.ts` → `UserFindManyValidationSchema`
- Inputs: `inputs/UserWhereInput.schema.ts` → `UserWhereInputSchema`
- Enums: `enums/Role.enum.ts` → `RoleEnumSchema`

# Optional Field Behavior

The `optionalFieldBehavior` configuration option controls how optional Prisma fields (marked with `?`) are mapped to Zod validation schemas.

## Configuration Options

| Value               | Zod Output    | TypeScript Type          | Description                                            |
| ------------------- | ------------- | ------------------------ | ------------------------------------------------------ |
| `nullish` (default) | `.nullish()`  | `T \| null \| undefined` | Field can be omitted, explicitly null, or have a value |
| `optional`          | `.optional()` | `T \| undefined`         | Field can be omitted or have a value, but not null     |
| `nullable`          | `.nullable()` | `T \| null`              | Field must be present but can be null or have a value  |

## Usage

### Generator Block Configuration

Configure directly in your `schema.prisma`:

```prisma
generator zod {
  provider = "prisma-zod-generator"
  optionalFieldBehavior = "optional"
}
```

### JSON Configuration

Or in your `zod-generator.config.json`:

```json
{
  "optionalFieldBehavior": "nullish"
}
```

## Examples

Given this Prisma model:

```prisma
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?  // Optional field
  bio   String?  // Optional field
}
```

### Nullish Behavior (Default)

```typescript
// Generated schema
const UserCreateInputSchema = z.object({
  email: z.string(),
  name: z.string().nullish(),
  bio: z.string().nullish()
});

// Valid inputs
{ email: "test@example.com", name: "John", bio: "Developer" }
{ email: "test@example.com", name: null, bio: undefined }
{ email: "test@example.com" } // name and bio omitted
```

### Optional Behavior

```typescript
// Generated schema
const UserCreateInputSchema = z.object({
  email: z.string(),
  name: z.string().optional(),
  bio: z.string().optional()
});

// Valid inputs
{ email: "test@example.com", name: "John", bio: "Developer" }
{ email: "test@example.com", name: undefined, bio: undefined }
{ email: "test@example.com" } // name and bio omitted

// Invalid input
{ email: "test@example.com", name: null } // ❌ null not allowed
```

### Nullable Behavior

```typescript
// Generated schema
const UserCreateInputSchema = z.object({
  email: z.string(),
  name: z.string().nullable(),
  bio: z.string().nullable()
});

// Valid inputs
{ email: "test@example.com", name: "John", bio: "Developer" }
{ email: "test@example.com", name: null, bio: null }

// Invalid input
{ email: "test@example.com" } // ❌ name and bio must be present
```

## Type Compatibility

All three behaviors maintain full compatibility with Prisma's generated TypeScript types:

```typescript
import { User } from '@prisma/client';

// All generated schemas are compatible with Prisma types
const prismaUser: Prisma.UserCreateInput = {
  email: 'test@example.com',
  name: null, // Prisma allows null for optional fields
};

// Works with any optionalFieldBehavior setting
UserCreateInputSchema.parse(prismaUser); // ✅ Always valid
```

## Use Cases

### API Validation

**Nullish** (default) is recommended for most API scenarios where clients can:

- Omit fields entirely
- Explicitly send null values
- Send actual values

### Strict Input Validation

**Optional** is useful when you want to:

- Allow fields to be omitted
- Reject explicit null values
- Maintain clean undefined-only semantics

### Always-Present Fields

**Nullable** is suitable when:

- Fields must always be included in requests
- Null is a meaningful value
- You want to distinguish between "not set" and "explicitly null"

## Object Schemas: Optional vs Nullable (Behavior Note)

For input object schemas under `objects/` (e.g., `UserCreateInput.schema.ts`, `PostUpdateInput.schema.ts`), the generator applies a policy that aligns Prisma optionality with practical API usage:

- Optional non‑relation fields (scalars/enums/unions) are emitted as `.optional().nullable()` to accept both omission and explicit `null`.
- Optional relation‑shaped fields remain `.optional()` only and reject `null` (use omission to skip).

Examples:

```ts
// Optional non-relation scalar
name: z.string().optional().nullable()

// Optional non-relation union (e.g., update operations)
title: z.union([z.string(), TitleFieldUpdateOperationsInputObjectSchema]).optional().nullable()

// Optional relation-shaped fields
author: z.lazy(() => UserCreateNestedOneWithoutPostsInputObjectSchema).optional()         // ✅ undefined ok
// author: null  // ❌ invalid, use omission instead
```

Additionally, in filter/where inputs, optional non-relation unions (e.g., `AND`, `OR`, `NOT`, or scalar filter unions) are treated as optional + nullable to allow `null` as a shorthand for “not applied”.

Rationale:

- Prisma optional fields often map to nullable columns; allowing `null` and omission improves ergonomics for JSON clients while keeping relation operations explicit and unambiguous.

This policy applies to object input schemas irrespective of `optionalFieldBehavior` (which continues to control pure model and variant schema generation).

## Migration

When changing `optionalFieldBehavior`, regenerate your schemas:

```bash
npx prisma generate
```

All behaviors are functionally equivalent for validation - the choice depends on your API design preferences.

# Configuration Precedence

Final config is assembled in stages:

1. Generator block options (Prisma `schema.prisma`) – highest priority.
2. JSON config file (explicit `config` path or auto-discovered: `zod-generator.config.json`, `prisma/config.json`, `config.json`).
3. Internal defaults (`processConfiguration`).

## Config File Path Resolution

Config file paths are resolved **relative to the Prisma schema file directory**, not the project root:

```prisma title="prisma/schema.prisma"
generator zod {
  provider = "prisma-zod-generator"
  config   = "./my-config.json"  // → prisma/my-config.json
}
```

```prisma title="apps/api/schema.prisma"
generator zod {
  provider = "prisma-zod-generator"
  config   = "../../shared/zod.config.json"  // → shared/zod.config.json
}
```

This allows flexible config placement in monorepos and projects with custom schema locations.

## Output Path Resolution

Output path resolution is deferred until after merging so a JSON `output` applies when the generator block omits `output`. Like config paths, output paths are also resolved relative to the schema file location.

Conflict warnings are logged (file layout options) via `warnOnFileLayoutConflicts`—generator block wins.

Legacy flags (e.g. `isGenerateSelect`, `isGenerateInclude`) are folded into the unified config; minimal mode forcibly disables select/include even if legacy flags true.

# JSON Schema IntelliSense

The generator ships a full [JSON Schema draft‑07](https://json-schema.org/) definition for every config option. Point your config files at it once and editors, CI scripts, and custom tooling all get the same contract the generator enforces internally.

## Quick Start

1. Make sure `prisma-zod-generator` is installed (the schema is published with every npm release under `lib/config/schema.json`).
2. Open the config file you pass through the Prisma generator block (for example `prisma/config.json`, `zod-generator.config.json`, or whatever you set via `config = "./..."`).
3. Add a `$schema` field that points to the installed package:

```json title="prisma/config.json"
{
  "$schema": "../node_modules/prisma-zod-generator/lib/config/schema.json",
  "mode": "full",
  "pureModels": true
}
```

Save the file and your editor immediately enables IntelliSense, hover docs, and red squiggles for invalid values.

## Picking the Right Path

- **Relative to config file** – Recommended because it survives CI and other machines. Use `../node_modules/...` if your config file sits inside the `prisma/` directory, or `./node_modules/...` if it lives at the project root.
- **Absolute path** – Works for quick tests but breaks across machines. Prefer relative paths once you confirm things locally.
- **Hosted copy** – If you host the schema at a stable URL (for example on your docs site or an internal CDN), set `$schema` to the HTTPS URL. Any consumer that understands JSON Schema will pull it remotely.

## Programmatic Validation

Need to fail CI when someone pushes an invalid config? Reuse the same schema through the compiled validator:

```ts title="scripts/validate-config.ts"
import { readFileSync } from 'node:fs';
import { ConfigurationValidator } from 'prisma-zod-generator/lib/config/validator.js';

const configPath = process.argv[2] ?? './prisma/config.json';
const validator = new ConfigurationValidator();
const config = JSON.parse(readFileSync(configPath, 'utf8'));
const result = validator.validate(config);

if (!result.valid) {
  console.error('❌ Invalid Prisma Zod Generator config:');
  console.error(result.errors);
  process.exit(1);
}

console.log('✅ Config looks good');
```

Pair this with the `$schema` hint so editors catch problems before CI does.

Once the `$schema` field is in place, every upgrade automatically refreshes the schema definition because the path always points to the version installed in `node_modules`.

# Strict Mode Configuration

The strict mode feature provides granular control over when `.strict()` is applied to generated Zod schemas. By default, all schemas include `.strict()` for backward compatibility, but you can now configure this behavior globally, per-model, per-operation, or per-variant.

## Overview

Zod's `.strict()` method prevents unknown properties from being accepted during validation. While this provides type safety, there are scenarios where you might want more flexible validation:

- **API integration**: External APIs might return additional fields
- **Gradual migration**: Transitioning from loose to strict validation
- **Development flexibility**: Allowing extra fields during development

## Global Configuration

Configure strict mode globally for all schemas:

```json
{
  "strictMode": {
    "enabled": true,        // Global default for all schemas
    "operations": true,     // CRUD operation schemas (findMany, create, etc.)
    "objects": true,        // Input object schemas (WhereInput, CreateInput, etc.)
    "variants": true        // Variant schemas (pure, input, result)
  }
}
```

### Default Behavior

Without any `strictMode` configuration, all schemas include `.strict()` for backward compatibility:

```typescript
// Default behavior
export const UserCreateInputSchema = z.object({
  name: z.string(),
  email: z.string()
}).strict(); // ← Applied by default
```

### Disabling Globally

To disable strict mode for all schemas:

```json
{
  "strictMode": {
    "enabled": false
  }
}
```

```typescript
// Result: no .strict() suffix
export const UserCreateInputSchema = z.object({
  name: z.string(),
  email: z.string()
}); // ← No .strict()
```

## Schema Type Control

Control strict mode for specific schema types:

```json
{
  "strictMode": {
    "enabled": true,
    "operations": true,    // findMany, create, update operations
    "objects": false,      // WhereInput, CreateInput objects
    "variants": true       // Pure, input, result variants
  }
}
```

This configuration results in:

```typescript
// Operations: strict (operations: true)
export const FindManyUserArgsSchema = z.object({
  where: UserWhereInputSchema.optional()
}).strict(); // ← Has .strict()

// Objects: not strict (objects: false)
export const UserWhereInputSchema = z.object({
  name: z.string().optional()
}); // ← No .strict()

// Variants: strict (variants: true)
export const UserPureSchema = z.object({
  id: z.number(),
  name: z.string()
}).strict(); // ← Has .strict()

// Enums: always strict (inherently strict, no .strict() method)
export const StatusSchema = z.enum(['ACTIVE', 'INACTIVE']); // ← No .strict() needed
```

## Model-Level Configuration

Override strict mode settings for specific models:

```json
{
  "strictMode": {
    "enabled": true,
    "operations": false,
    "objects": false
  },
  "models": {
    "User": {
      "strictMode": {
        "enabled": true,      // Enable for User model
        "operations": true,   // Override: User operations get .strict()
        "objects": true      // Override: User objects get .strict()
      }
    },
    "Post": {
      "strictMode": {
        "enabled": false     // Disable all strict mode for Post
      }
    }
  }
}
```

Result:

- **User**: All schemas get `.strict()` (model override)
- **Post**: No schemas get `.strict()` (model disabled)
- **Other models**: Follow global settings (operations and objects disabled)

## Operation-Level Control

Control strict mode for specific operations within a model:

```json
{
  "models": {
    "User": {
      "strictMode": {
        "operations": ["findMany", "create"],  // Only these operations get .strict()
        "exclude": ["update"]                  // Exclude update operations
      }
    }
  }
}
```

```typescript
// Gets .strict() (in operations list)
export const FindManyUserArgsSchema = z.object({...}).strict();

// Gets .strict() (in operations list)
export const CreateOneUserArgsSchema = z.object({...}).strict();

// No .strict() (not in operations list)
export const UpdateOneUserArgsSchema = z.object({...});

// No .strict() (in exclude list)
export const UpdateManyUserArgsSchema = z.object({...});
```

### Operation Names

Valid operation names include:

- `findUnique`, `findUniqueOrThrow`
- `findFirst`, `findFirstOrThrow`
- `findMany`
- `create`, `createMany`, `createManyAndReturn`
- `update`, `updateMany`, `updateManyAndReturn`
- `delete`, `deleteMany`
- `upsert`
- `aggregate`, `groupBy`, `count`

## Variant-Level Control

Configure strict mode for specific variants:

### Global Variant Settings

```json
{
  "strictMode": {
    "variants": false  // Disable for all variants globally
  },
  "variants": {
    "pure": {
      "enabled": true,
      "strictMode": true    // Override: pure variants get .strict()
    },
    "input": {
      "enabled": true,
      "strictMode": false   // Explicit: input variants don't get .strict()
    },
    "result": {
      "enabled": true
      // Uses global variants setting (false)
    }
  }
}
```

### Model-Specific Variant Settings

```json
{
  "models": {
    "User": {
      "strictMode": {
        "variants": {
          "pure": true,     // User pure variant gets .strict()
          "input": false,   // User input variant doesn't get .strict()
          "result": null    // Uses global/parent setting
        }
      }
    }
  }
}
```

## Configuration Hierarchy

Strict mode settings follow a hierarchy (most specific wins):

1. **Operation-level** (`models.ModelName.strictMode.operations` array)
2. **Model-level** (`models.ModelName.strictMode.*`)
3. **Global schema type** (`strictMode.operations`, `strictMode.objects`, etc.)
4. **Global default** (`strictMode.enabled`)

### Example Hierarchy

```json
{
  "strictMode": {
    "enabled": false,      // 4. Global default: disabled
    "operations": true     // 3. Global operations: enabled
  },
  "models": {
    "User": {
      "strictMode": {
        "enabled": true,         // 2. Model-level: enabled
        "operations": ["findMany"] // 1. Operation-level: only findMany
      }
    }
  }
}
```

Result for User model:

- `findMany`: **strict** (operation-level wins)
- `create`: **not strict** (not in operation list)
- `objects`: **strict** (inherits from model-level enabled)

## Common Patterns

### API-Friendly Configuration

Disable strict mode for operations but keep it for internal schemas:

```json
{
  "strictMode": {
    "enabled": true,
    "operations": false,  // Allow extra fields in API requests
    "objects": true,      // Keep strict for internal validation
    "variants": true
  }
}
```

### Development vs Production

Development configuration (more permissive):

```json
{
  "strictMode": {
    "enabled": false,
    "operations": false,
    "objects": false,
    "variants": true     // Keep variants strict for type safety
  }
}
```

Production configuration (strict validation):

```json
{
  "strictMode": {
    "enabled": true,
    "operations": true,
    "objects": true,
    "variants": true
  }
}
```

### Gradual Migration

Start with loose validation and gradually enable strict mode:

```json
{
  "strictMode": {
    "enabled": false  // Start permissive
  },
  "models": {
    "User": {
      "strictMode": {
        "enabled": true  // Migrate User model first
      }
    }
  }
}
```

## Backward Compatibility

The strict mode feature maintains full backward compatibility:

- **No configuration**: All schemas get `.strict()` (existing behavior)
- **Existing projects**: Continue working without changes
- **New projects**: Can opt into flexible validation

## Examples

### Basic Usage

Disable strict mode for all operations but keep it for objects:

```json
{
  "strictMode": {
    "enabled": true,
    "operations": false,
    "objects": true
  }
}
```

### Advanced Model Configuration

Different strict mode settings per model:

```json
{
  "strictMode": {
    "enabled": false,
    "operations": false,
    "objects": false
  },
  "models": {
    "User": {
      "strictMode": {
        "enabled": true,
        "operations": ["findMany", "create"],
        "objects": true,
        "variants": {
          "pure": true,
          "input": false
        }
      }
    },
    "Post": {
      "strictMode": {
        "operations": true,
        "exclude": ["update", "delete"]
      }
    }
  }
}
```

### Variant-Specific Configuration

```json
{
  "strictMode": {
    "enabled": true,
    "variants": false
  },
  "variants": {
    "pure": {
      "enabled": true,
      "strictMode": true
    },
    "input": {
      "enabled": true,
      "strictMode": false
    }
  },
  "models": {
    "User": {
      "strictMode": {
        "variants": {
          "result": true
        }
      }
    }
  }
}
```

## Migration Guide

### From Always Strict (Default)

If you're upgrading and want to maintain existing behavior, no changes are needed. All schemas will continue to include `.strict()`.

### To Flexible Validation

To allow extra fields in API requests:

```json
{
  "strictMode": {
    "operations": false,  // Allow extra fields in operation inputs
    "objects": true       // Keep strict for internal objects
  }
}
```

### Per-Model Migration

Migrate models gradually:

```json
{
  "strictMode": {
    "enabled": true  // Keep existing strict behavior
  },
  "models": {
    "NewModel": {
      "strictMode": {
        "operations": false  // New model allows extra fields
      }
    }
  }
}
```

## Best Practices

1. **Start Conservative**: Begin with strict mode enabled and selectively disable where needed
2. **Test Thoroughly**: Validate that your application handles extra fields correctly when strict mode is disabled
3. **Document Decisions**: Comment your configuration to explain why certain models/operations have different strict mode settings
4. **Environment-Specific**: Consider different configurations for development vs production
5. **Gradual Migration**: When changing existing projects, migrate model by model rather than all at once

## Troubleshooting

### Schemas Still Have .strict()

Check the configuration hierarchy. More specific settings override general ones:

```json
{
  "strictMode": {
    "enabled": false  // This might be overridden
  },
  "models": {
    "User": {
      "strictMode": {
        "enabled": true  // This overrides the global setting
      }
    }
  }
}
```

### Configuration Not Applied

1. Ensure your configuration file is properly referenced in the Prisma schema
2. Check for JSON syntax errors
3. Verify the configuration file path is correct
4. Run generation again after configuration changes

### Unexpected Behavior

- **Model not found**: Ensure model names match exactly (case-sensitive)
- **Operation not working**: Check operation names against the valid list above
- **Variant issues**: Verify variant is enabled before configuring strict mode

# Variants System

Two forms:

1. Object-based (`variants.pure/input/result`) – enable flags + suffix + excludeFields + partial.
2. Array-based custom variants – each element: `{ name, suffix?, exclude?, additionalValidation?, makeOptional?, transformRequiredToOptional?, transformOptionalToRequired?, removeValidation?, partial? }`.

Generation behavior:

- Skips entirely if `emit.variants=false` or single-file mode active (variants suppressed in strict single-file).
- Pure models may still generate separately (`emit.pureModels`).
- `pureVariantOnlyMode` & `pureModelsOnlyMode` heuristics reduce other schema categories.

Custom variant field building applies:

- Base inferred zod type
- Optionality transforms
- Additional validations from variant def or `@zod` doc comments
- Enum imports resolved relative to variants directory

## Partial Flag

The `partial` flag automatically applies `.partial()` to generated Zod schemas, making all fields optional. This is useful for update operations where you only want to provide some fields.

### Configuration

Object-based variants:

```json
{
  "variants": {
    "input": {
      "enabled": true,
      "partial": true
    },
    "result": {
      "enabled": true,
      "partial": false
    }
  }
}
```

Array-based custom variants:

```json
{
  "variants": [
    {
      "name": "UpdateInput",
      "suffix": "UpdateInput",
      "partial": true
    },
    {
      "name": "CreateInput",
      "suffix": "CreateInput",
      "partial": false
    }
  ]
}
```

### Example Output

With `partial: true`:

```typescript
export const UserInputSchema = z.object({
  id: z.number().int(),
  name: z.string(),
  email: z.string().email()
}).strict().partial();
```

With `partial: false` (default):

```typescript
export const UserResultSchema = z.object({
  id: z.number().int(),
  name: z.string(),
  email: z.string().email()
}).strict();
```

### Use Cases

- **Update operations**: Use `partial: true` for PATCH/PUT endpoints where users provide only fields to update
- **Create operations**: Use `partial: false` for POST endpoints where all required fields must be provided
- **Form handling**: Partial schemas for progressive form completion
- **API flexibility**: Allow clients to send minimal payloads

# API Docs Pack

> **Available in:** Professional, Business, Enterprise tiers

Auto-generate OpenAPI v3 specifications and a fully-functional mock server from your Prisma schema. Perfect for frontend development, testing, and API documentation.

## Why Use API Docs Pack

**Problem**: API documentation gets out of sync with reality:

- Manually written OpenAPI specs drift from actual implementation
- Frontend teams blocked waiting for backend APIs
- No easy way to test UI against realistic API responses
- Documentation maintenance is time-consuming

**Solution**: Generate accurate OpenAPI specs and a working mock server directly from your Prisma schema.

### Benefits

- **Always Accurate**: Docs generated from source of truth (Prisma schema)
- **Instant Mock Server**: Test UIs without waiting for backend
- **Swagger UI Included**: Interactive API explorer out of the box
- **Zero Maintenance**: Regenerate when schema changes

## Prerequisites

```bash
# Install Express for mock server
pnpm add express @prisma/client
pnpm add -D @types/express
pnpm add -D tsx  # Required to run TypeScript mock server/tests

# PZG Pro license required
```

## Generate

Add to your `schema.prisma`:

```prisma
generator pzgPro {
  provider = "node ./node_modules/prisma-zod-generator/lib/cli/pzg-pro.js"
  output = "./generated/pro"
  enableApiDocs = true
}
```

Then run:

```bash
prisma generate
```

### Generated Files

```
generated/
  pro/
    api-docs/
      openapi.json          # OpenAPI v3 specification
      openapi.yaml          # OpenAPI v3 (YAML format)
      mock-server.js        # Express mock server
      index.html            # Swagger UI
      sdk.ts                # TypeScript SDK client
      examples/             # Example requests
      docs/                 # Static documentation
      USAGE.md              # Usage guide
```

## Basic Usage

### Running the Mock Server

```bash
# From project root
cd generated/pro/api-docs
node mock-server.js

# Server starts at http://localhost:3001
```

### Accessing Swagger UI

Open [http://localhost:3001/docs](http://localhost:3001/docs) in your browser to:

- Interactively explore your API
- Try out endpoints
- View request/response schemas

### Generated Endpoints

The mock server generates standard REST endpoints aligned with your Prisma models:

```bash
# Users API (example)
GET /api/users         # List users
GET /api/users/:id     # Get single user
POST /api/users        # Create user
PUT /api/users/:id     # Update user
DELETE /api/users/:id  # Delete user

# Posts API (example)
GET /api/posts
GET /api/posts/:id
POST /api/posts
PUT /api/posts/:id
DELETE /api/posts/:id
```

## Integration

### Frontend Development

```tsx
// Point to mock server during development
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001'

const users = await fetch(`${API_URL}/api/users`).then(r => r.json())
```

### Testing

```ts
// Use mock server in integration tests
beforeAll(async () => {
  // Start mock server
  mockServer = spawn('npx', ['tsx', 'generated/api-docs/mock-server.ts'])
  await new Promise(resolve => setTimeout(resolve, 2000))
})

test('fetches users', async () => {
  const response = await fetch('http://localhost:3001/api/users')
  const users = await response.json()
  expect(Array.isArray(users)).toBe(true)
})
```

## See Also

- [SDK Publisher](./sdk.md) - Generate typed clients from OpenAPI
- [Contract Testing](./contracts.md) - Verify API contracts

# Contract Testing Pack

> **Available in:** Business, Enterprise tiers

Consumer/provider contract tests and JSON definitions to verify API compatibility using Pact.js.

## Why Use Contract Testing

**Problem**: API changes break integrations:

- Backend changes break frontend without warning
- No way to verify API contracts are maintained
- Integration tests require full backend setup

**Solution**: Generate Pact.js consumer/provider tests from your schema to catch breaking changes early.

### Benefits

- **Catch Breaking Changes**: Before deployment
- **Independent Development**: Frontend/backend teams work in parallel
- **Contract as Documentation**: Living API contracts

## Prerequisites

```bash
# Install Pact.js & Jest helpers
pnpm add -D @pact-foundation/pact jest jest-pact @prisma/client

# PZG Pro license required
```

## Generate

Add to your `schema.prisma`:

```prisma
generator pzgPro {
  provider = "node ./node_modules/prisma-zod-generator/lib/cli/pzg-pro.js"
  output = "./generated/pro"
  enableContracts = true
}
```

Then run:

```bash
prisma generate
```

### Generated Files

```
generated/
  pro/
    contracts/
      consumer/           # Consumer tests
      provider/           # Provider tests
      definitions/        # JSON contract definitions
```

## Run Tests

Add these scripts to your `package.json`:

```json
{
  "scripts": {
    "test:contract:consumer": "jest generated/pro/contracts/consumer",
    "test:contract:provider": "jest generated/pro/contracts/provider"
  }
}
```

Then run:

```bash
# Run consumer tests
pnpm run test:contract:consumer

# Run provider tests
pnpm run test:contract:provider
```

> **Note**: The generator creates test files but you need to manually add the npm scripts above to your package.json.

## Consumer Example

```ts
// Consumer test expects specific API response format
import { pactWith } from 'jest-pact'

pactWith({ consumer: 'WebApp', provider: 'UserAPI' }, (interaction) => {
  describe('GET /users/:id', () => {
    beforeEach(() => {
      interaction
        .given('user 123 exists')
        .uponReceiving('a request for user 123')
        .withRequest({ method: 'GET', path: '/users/123' })
        .willRespondWith({
          status: 200,
          body: {
            id: '123',
            email: 'user@example.com',
            name: 'John Doe'
          }
        })
    })

    it('returns user data', async () => {
      const response = await fetch('http://localhost:8989/users/123')
      const user = await response.json()
      expect(user.id).toBe('123')
    })
  })
})
```

## See Also

- [SDK Publisher](./sdk.md) - Generate typed SDK
- [API Docs Pack](./api-docs.md) - OpenAPI specifications

# Data Factories

> **Available in:** Business, Enterprise tiers

Type-safe builders for realistic mock data with optional Prisma persistence.

## Why Use Data Factories

**Problem**: Creating test data is tedious:

- Manually writing test data for every test
- Data doesn't match real schema structure
- Hard to create valid related data
- No easy way to persist to database

**Solution**: Generate factories that build type-safe test data with realistic values.

### Benefits

- **Type-Safe**: Follows your Prisma schema exactly
- **Realistic Data**: Sensible defaults for all fields
- **Relationships**: Handle nested data easily
- **Optional Persistence**: Build in-memory or save to database

## Prerequisites

```bash
# Core dependencies
pnpm add @prisma/client

# PZG Pro license required
```

## Generate

Add to your `schema.prisma`:

```prisma
generator pzgPro {
  provider = "node ./node_modules/prisma-zod-generator/lib/cli/pzg-pro.js"
  output = "./generated/pro"
  enableFactories = true
}
```

Then run:

```bash
prisma generate
```

### Generated Files

```
generated/
  pro/
    factories/
      factories.ts         # Factory functions for each model
```

## Basic Usage

```ts
import { userFactory, postFactory } from '@/generated/pro/factories/factories'

// Build in-memory (no database)
const user = userFactory.build({
  email: 'test@example.com'
})

// Build many
const users = userFactory.buildMany(10)

// With custom values
const admin = userFactory.build({
  email: 'admin@example.com',
  role: 'ADMIN'
})
```

### Persistence (Optional)

When Prisma client is available:

```ts
// Create in database
const user = await userFactory.create({
  email: 'db@example.com'
})

// Create many
const users = await userFactory.createMany(5)

// With relationships
const userWithPosts = await userFactory.create({
  posts: {
    create: [
      postFactory.build({ title: 'First Post' }),
      postFactory.build({ title: 'Second Post' })
    ]
  }
})
```

## Testing Example

```ts
import { describe, it, expect } from 'vitest'
import { userFactory } from '@/generated/pro/factories/factories'

describe('User API', () => {
  it('creates a user', async () => {
    const userData = userFactory.build()
    
    const response = await fetch('/api/users', {
      method: 'POST',
      body: JSON.stringify(userData)
    })
    
    expect(response.ok).toBe(true)
  })
})
```

## See Also

- [Performance Pack](./performance.md) - Validate large datasets
- [Contract Testing](./contracts.md) - Test with factory data

# Form UX Pack

> **Available in:** Starter, Professional, Business, Enterprise tiers

Schema-driven React forms with automatic validation. Generate fully-typed form components from your Prisma schema using React Hook Form and Zod.

## Why Use Form UX Pack

**Problem**: Building forms is repetitive and error-prone:

- Manually creating form components for each model
- Writing validation logic that duplicates schema rules
- Keeping forms in sync with database schema changes
- Handling complex nested relationships
- Managing form state, errors, and submissions

**Solution**: Auto-generate type-safe form components from your Prisma schema with built-in validation, error handling, and customizable UI.

### Benefits

- **Zero Boilerplate**: Forms generated from schema
- **Type Safety**: Full TypeScript from database to UI
- **Auto Validation**: Zod schemas automatically applied
- **Customizable UI**: Bring your own components (shadcn/ui, MUI, etc.)
- **Nested Relations**: Handle complex data structures
- **Form State**: Built-in loading, error, and success states

## Prerequisites

```bash
# Core dependencies
pnpm add react react-dom react-hook-form @hookform/resolvers zod @prisma/client

# UI library (optional - example with shadcn/ui)
pnpm add class-variance-authority clsx tailwind-merge
npx shadcn@latest init

# PZG Pro license required
```

## Generate

Add to your `schema.prisma`:

```prisma
generator pzgPro {
  provider = "node ./node_modules/prisma-zod-generator/lib/cli/pzg-pro.js"
  output = "./generated/pro"
  enableForms = true

  // Optional advanced config (stringified JSON)
  // forms = "{ \"uiLibrary\": \"shadcn\", \"enableI18n\": true, \"i18nNamespace\": \"forms\", \"generateTests\": true }"
}
```

> Pass additional options (UI library, i18n, tests, etc.) through the `forms` JSON string. All keys must be valid JSON and wrapped in quotes inside the Prisma schema.

Then run:

```bash
prisma generate
```

> **Note**: The generator supports multiple UI libraries. Use `barebones` for framework-agnostic forms, or specify `shadcn`, `mantine`, `chakra`, or `mui` for framework-specific components.

### Generated Files

```
generated/
  pro/
    forms/
      components/
        UserForm.tsx         # User form component
        PostForm.tsx         # Post form component
      validation/
        UserValidation.ts    # User validation helpers
        PostValidation.ts    # Post validation helpers
      i18n/                  # i18n translation keys (if enabled)
        user.json
        post.json
      __tests__/             # Form tests (if enabled)
        UserForm.test.tsx
        PostForm.test.tsx
      zod.ts                 # Zod schemas for all models
      index.ts               # Exports all forms and validation
      README.md              # Usage documentation
```

## Basic Usage

```tsx
// app/users/create/page.tsx
import { UserForm } from '@/generated/pro/forms'

export default function CreateUserPage() {
  return (
    <UserForm
      defaultValues={{
        email: '',
        name: ''
      }}
      onSubmit={async (data) => {
        // Send to API
        const response = await fetch('/api/users', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(data)
        })

        if (response.ok) {
          console.log('User created')
        }
      }}
    />
  )
}
```

### Edit Form Example

```tsx
// app/users/[id]/edit/page.tsx
import { UserForm } from '@/generated/pro/forms'

export default async function EditUserPage({ params }: { params: { id: string } }) {
  const user = await fetch(`/api/users/${params.id}`).then(r => r.json())

  return (
    <UserForm
      defaultValues={user}
      onSubmit={async (data) => {
        await fetch(`/api/users/${user.id}`, {
          method: 'PUT',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(data)
        })
      }}
    />
  )
}
```

## Integration Notes

### Validation & Controllers

Generated forms rely on `react-hook-form` with Zod validation. By default the generator emits `<FormField>` components that wrap `Controller` for you. If you prefer manual `register()` calls (e.g., for simple text inputs), you can skip the generated wrappers and wire up `useForm` directly—just make sure to use the same Zod resolver.

### Schema Imports

The generated forms import validation schemas from your Prisma Zod output. Prefer importing from a generated aggregator (e.g., `prisma/zod/index.ts`) that maps long object names to short forms like `UserCreateInputSchema`.

### Nested Relations

If a Prisma create schema includes nested relations, provide a compatible default (e.g., `{}`) or render nested form fields to handle the relationship data.

### Customizing UI

The generated form components are designed to work with your UI library of choice. You can:

- Swap out the default input components
- Add custom styling and classes
- Integrate with component libraries like shadcn/ui, MUI, Chakra, etc.
- Customize error display and form layout

## Example: shadcn/ui Integration

```tsx
// Example using RHF register + shadcn/ui inputs
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import { UserCreateInputSchema } from '@/generated/pro/forms/schemas'

import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Button } from '@/components/ui/button'

type UserFormValues = z.infer<typeof UserCreateInputSchema>

export function UserForm({ defaultValues, onSubmit }: UserFormProps) {
  const form = useForm<UserFormValues>({
    resolver: zodResolver(UserCreateInputSchema),
    defaultValues,
  })

  return (
    <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
      <div className="space-y-2">
        <Label htmlFor="email">Email</Label>
        <Input id="email" type="email" {...form.register('email')} />
        {form.formState.errors.email && (
          <p className="text-sm text-red-500">
            {form.formState.errors.email.message}
          </p>
        )}
      </div>

      <Button type="submit" disabled={form.formState.isSubmitting}>
        Submit
      </Button>
    </form>
  )
}
```

## See Also

- [Server Actions Pack](./server-actions.md) - Integrate with Next.js server actions
- [API Docs Pack](./api-docs.md) - Test forms against mock API
- [SDK Publisher](./sdk.md) - Use generated SDK for form submissions

# Drift Guard

> **Available in:** Professional, Business, Enterprise tiers

CI helper to catch breaking changes in generated outputs (schema/API drift).

## What It Does

- Compares generated output between `--base` and `--head` branches
- Detects breaking changes in schemas, types, and APIs
- Produces GitHub-formatted reports for PR comments

## Prerequisites

```bash
# PZG Pro license required
```

## Generate & Run

```bash
pzg-pro guard --schema=./prisma/schema.prisma --base=origin/main --head=HEAD --format=github
```

### Command Options

- `--schema <path>` – Path to your Prisma schema (defaults to `./prisma/schema.prisma`).
- `--base <ref>` – Git reference to compare from (defaults to `origin/main`).
- `--head <ref>` – Git reference to compare to (defaults to `HEAD`).
- `--format <github|json|text>` – Output format (defaults to `github`).
- `--json`, `--text`, `--github` – Shortcut flags for `--format`.
- `--strict` – Treat warnings as breaking changes.
- `--allowed-break <identifier>` – Whitelist specific breaking change identifiers (repeatable).
- `--help` – Show usage and exit.

The command runs entirely on the command line—no custom scripts required. Make sure you execute it inside a git repo (so the base ref can be resolved) and with a valid PZG Pro license available (`PZG_LICENSE_KEY`).

Under the hood the CLI loads the DMMF for the base and head schemas, runs `validateDriftFromDMMF`, and prints a GitHub-friendly report. A non-zero exit code indicates breaking changes.

:::tip Git history
Fetch the full history (`fetch-depth: 0`) before running the command in CI so the base ref’s schema can be read.
:::

### Programmatic API

Prefer to orchestrate things yourself? Import `validateDriftFromDMMF` from `prisma-zod-generator/pro` and feed it the base/head DMMF documents alongside your generator configuration. The CLI is thin sugar over that helper.

## GitHub Actions

```yaml
name: PZG Drift Guard
on: [pull_request]
jobs:
  guard:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with: { version: 9 }
      - run: pnpm i --frozen-lockfile
      - run: pnpm tsx scripts/run-drift-guard.ts
```

In scripts you can check `result.changes` for the change identifiers used by `--allowed-break` (e.g., `model.User.field_removed`).

## See Also

- [Contract Testing](./contracts.md) - Test API contracts
- [SDK Publisher](./sdk.md) - Detect SDK breaking changes

# Multi-Tenant Kit

> **Available in:** Enterprise tier

Zod helpers to validate tenant context at API/UI boundaries for SaaS applications.

## Why Use Multi-Tenant Kit

**Problem**: Multi-tenant applications need strict data isolation:

- Tenant data must never leak across tenants
- Every request needs tenant validation
- UI needs tenant-aware components
- Manual tenant checks are error-prone

**Solution**: Generate Zod helpers that enforce tenant context validation at every API and UI boundary.

### Benefits

- **Strict Isolation**: Validate tenant access before data operations
- **Type-Safe**: Full TypeScript validation
- **Configurable Modes**: Strict, warn, or log violations
- **UI Integration**: React context provider for tenant state

## Prerequisites

```bash
# Core dependencies
pnpm add zod react @prisma/client

# PZG Pro license required
```

## Generate

Add to your `schema.prisma`:

```prisma
generator pzgPro {
  provider = "node ./node_modules/prisma-zod-generator/lib/cli/pzg-pro.js"
  output = "./generated/pro"
  enableMultiTenant = true
}
```

Then run:

```bash
prisma generate
```

### Generated Files

```
generated/
  pro/
    multi-tenant/
      schemas/
        tenant-schemas.ts     # Tenant-aware Zod schemas
      middleware/
        prisma-middleware.ts  # Prisma middleware for tenant filtering
      extensions/
        prisma-extension.ts   # Prisma client extensions
      utils/
        validation.ts         # Validation utilities
        context.ts            # Tenant context helpers
      types/
        tenant-types.ts       # TypeScript types
      README.md               # Usage documentation
```

## Basic Usage

```ts
import { validateTenantAccess } from '@/generated/pro/multi-tenant/utils/validation'

// Modes: 'strict' | 'warn' | 'log'
const isValid = validateTenantAccess(
  { tenantId: 't1' },  // Request context
  't1',                 // Expected tenant
  'strict'              // Mode
)

if (!isValid) {
  throw new Error('Tenant mismatch')
}
```

### Validation Modes

- **strict**: Throws error on mismatch
- **warn**: Logs warning but continues
- **log**: Logs info for debugging

## UI Pattern

Provide a `TenantProvider` with the current tenant and refine schemas based on it:

```tsx
// Example tenant provider pattern
import { TenantProvider } from '@/generated/pro/multi-tenant/schemas/tenant-schemas'

export default function App() {
  const tenant = getCurrentTenant() // From auth/session

  return (
    <TenantProvider value={{ tenantId: tenant.id }}>
      <YourApp />
    </TenantProvider>
  )
}
```

See generated comments in the file for more integration patterns.

## See Also

- [PostgreSQL RLS](./postgres-rls.md) - Database-level tenant isolation
- [Policies & Redaction](./policies.md) - Field-level access control

# Pro Features Overview

Upgrade the core generator with production‑ready feature packs. Generate UI, SDKs, docs, security helpers, CI tooling — all in minutes.

import Link from '@docusaurus/Link';
import tiersImg from '@site/static/img/tiers.png';

## How to Get Pro Features

Purchase any tier through GitHub Sponsors and get started in minutes:

<div style={{ display: 'flex', gap: '1rem', margin: '2rem 0', flexWrap: 'wrap' }}>
  <Link className="button button--primary button--lg" to="https://github.com/sponsors/omar-dulaimi" style={{ textDecoration: 'none' }}>
    💎 Purchase on GitHub Sponsors
  </Link>

  <Link className="button button--secondary button--lg" to="/pricing" style={{ textDecoration: 'none' }}>
    📊 View Full Pricing
  </Link>
</div>

:::note Picking the right tier on GitHub Sponsors
The sponsors page has two tabs: **Monthly** and **One-time**. PZG plans live under the One-time tab
(second tab). Monthly supporter tiers such as **Pro (Individual)** do **not** include Prisma Zod Generator
licenses. Switch to the One-time tab and choose a yearly tier labeled **PZG Starter**, **PZG
Professional**, **PZG Business**, or **PZG Enterprise** when you need Pro features.
:::

<figure style={{ textAlign: 'center', margin: '1rem auto 2rem', maxWidth: 360 }}>
  <img
    src={tiersImg}
    alt="GitHub Sponsors One-time tab showing Prisma Zod Generator tiers"
    style={{
    width: '100%',
    borderRadius: '12px',
    boxShadow: '0 6px 30px rgba(15, 23, 42, 0.35)',
    border: '1px solid rgba(148, 163, 184, 0.4)',
  }}
  />

  <figcaption style={{ fontSize: '0.85rem', color: 'var(--ifm-color-emphasis-700)' }}>
    Switch to <strong>One-time</strong> to see the Prisma Zod Generator Starter, Professional, and Business tiers.
  </figcaption>
</figure>

**After purchasing:**

1. DM [@omardulaimidev on X](https://x.com/omardulaimidev) with your GitHub username
2. You'll receive your license key and setup instructions within 24 hours
3. Run `prisma-zod-generator license-check` to verify activation

### Available Tiers

| Tier             | Annual Price  | Features                                                      |
| ---------------- | ------------- | ------------------------------------------------------------- |
| **Starter**      | **$69/year**  | Server Actions, Forms                                         |
| **Professional** | **$199/year** | + SDK, API Docs, Policies, Guard, RLS, Performance            |
| **Business**     | **$599/year** | + Contracts, Factories, Priority response targets             |
| **Enterprise**   | **Custom**    | + Multi-Tenant, roadmap reviews, custom feature collaboration |

***

## Plan Comparison

| Feature Pack                        | Core (MIT) | Starter (`starter`) | Professional (`professional`) | Business (`business`) | Enterprise (`enterprise`) |
| ----------------------------------- | ---------- | ------------------- | ----------------------------- | --------------------- | ------------------------- |
| Server Actions                      | ✅          | ✅                   | ✅                             | ✅                     | ✅                         |
| Forms UX                            | ❌          | ✅                   | ✅                             | ✅                     | ✅                         |
| Policies & Redaction                | ❌          | ❌                   | ✅                             | ✅                     | ✅                         |
| Drift Guard                         | ❌          | ❌                   | ✅                             | ✅                     | ✅                         |
| PostgreSQL RLS                      | ❌          | ❌                   | ✅                             | ✅                     | ✅                         |
| Performance Pack                    | ❌          | ❌                   | ✅                             | ✅                     | ✅                         |
| SDK Publisher                       | ❌          | ❌                   | ✅                             | ✅                     | ✅                         |
| Contract Testing                    | ❌          | ❌                   | ❌                             | ✅                     | ✅                         |
| API Docs Pack                       | ❌          | ❌                   | ❌                             | ✅                     | ✅                         |
| Data Factories                      | ❌          | ❌                   | ❌                             | ✅                     | ✅                         |
| Multi-Tenant Kit                    | ❌          | ❌                   | ❌                             | ❌                     | ✅                         |
| Private Discord Channel             | ❌          | ✅                   | ✅                             | ✅                     | ✅                         |
| Priority Response Targets           | ❌          | ❌                   | ❌                             | ✅                     | ✅                         |
| Roadmap Reviews & Co-built Features | ❌          | ❌                   | ❌                             | ❌                     | ✅                         |

:::tip Choosing a plan
Starter is perfect for solo builders shipping typed Server Actions and forms. Professional unlocks security packs for production teams. Business adds integration and documentation tooling with faster support, and Enterprise layers on multi-tenant tooling plus roadmap collaboration.
:::

***

## Generate in minutes

```bash
# Check license
prisma-zod-generator license-check

# Enable the packs you need in schema.prisma
# (e.g., enableForms/enableSDK/enableApiDocs)

# Run Prisma generators
pnpm exec prisma generate
```

## Packs at a glance

<div className="feature-card-grid">
  <Link className="feature-card" to="./forms">
    <div className="feature-card__icon">🧩</div>
    <div className="feature-card__title">Forms UX</div>
    <div className="feature-card__desc">Schema‑driven React forms with Zod + RHF.</div>
  </Link>

  <Link className="feature-card" to="./sdk">
    <div className="feature-card__icon">🔌</div>
    <div className="feature-card__title">SDK Publisher</div>
    <div className="feature-card__desc">Typed HTTP client (ESM/CJS) with retry/timeouts.</div>
  </Link>

  <Link className="feature-card" to="./api-docs">
    <div className="feature-card__icon">📚</div>
    <div className="feature-card__title">API Docs</div>
    <div className="feature-card__desc">OpenAPI + runnable mock server for local dev.</div>
  </Link>

  <Link className="feature-card" to="./policies">
    <div className="feature-card__icon">🕵️</div>
    <div className="feature-card__title">Policies</div>
    <div className="feature-card__desc">PII redaction + policy helpers from annotations.</div>
  </Link>

  <Link className="feature-card" to="./postgres-rls">
    <div className="feature-card__icon">🧷</div>
    <div className="feature-card__title">Postgres RLS</div>
    <div className="feature-card__desc">RLS session context helpers + example SQL.</div>
  </Link>

  <Link className="feature-card" to="./multi-tenant">
    <div className="feature-card__icon">🏷️</div>
    <div className="feature-card__title">Multi‑Tenant</div>
    <div className="feature-card__desc">Tenant validation helpers for UI/API.</div>
  </Link>

  <Link className="feature-card" to="./performance">
    <div className="feature-card__icon">🚄</div>
    <div className="feature-card__title">Performance</div>
    <div className="feature-card__desc">Streaming validators for large arrays.</div>
  </Link>

  <Link className="feature-card" to="./factories">
    <div className="feature-card__icon">🏭</div>
    <div className="feature-card__title">Factories</div>
    <div className="feature-card__desc">Realistic test data builders.</div>
  </Link>

  <Link className="feature-card" to="./guard">
    <div className="feature-card__icon">🛡️</div>
    <div className="feature-card__title">Drift Guard</div>
    <div className="feature-card__desc">CI diffs to catch breaking changes.</div>
  </Link>

  <Link className="feature-card" to="./contracts">
    <div className="feature-card__icon">🤝</div>
    <div className="feature-card__title">Contracts</div>
    <div className="feature-card__desc">Consumer/provider tests + definitions.</div>
  </Link>

  <Link className="feature-card" to="./server-actions">
    <div className="feature-card__icon">🧠</div>
    <div className="feature-card__title">Server Actions</div>
    <div className="feature-card__desc">Typed actions validated with Zod.</div>
  </Link>
</div>

:::tip Pro Tip
You can generate multiple packs side‑by‑side — e.g., SDK + API Docs + Forms — to iterate UI against a mock server while the backend evolves.
:::

## Examples

Validate then submit (Forms + SDK)

```tsx
import { UserForm } from '../generated/forms'
import APIClient from '@your-org/api-sdk'

const client = new APIClient({ baseUrl: 'http://127.0.0.1:3001' })

export default function Page() {
  return (
    <UserForm
      defaultValues={{ email: 'test@example.com' }}
      onSubmit={async (data) => {
        const res = await client.createUser(data)
        if (!res.success) throw new Error(res.error)
      }}
    />
  )
}
```

# Performance Pack

> **Available in:** Professional, Business, Enterprise tiers

High-performance validation for large datasets with streaming validators, precompiled schemas, and progress tracking.

## Why Use Performance Pack

**Problem**: Standard validation is too slow for large datasets:

- Blocking validation of 100k+ records freezes applications
- Memory exhaustion when validating large arrays
- No progress feedback for long-running validation
- Single-threaded validation wastes CPU cores

**Solution**: Generate optimized streaming validators with chunking, concurrent processing, and progress hooks.

### Benefits

- **Streaming Validation**: Process data in chunks to avoid memory issues
- **Concurrent Processing**: Utilize multiple cores for parallel validation
- **Progress Tracking**: Real-time progress hooks for UX feedback
- **Memory Efficient**: Constant memory usage regardless of dataset size

## Prerequisites

```bash
# Core dependencies
pnpm add zod @prisma/client

# For streaming large files (optional)
pnpm add csv-parser stream-json

# PZG Pro license required
```

## Generate

Add to your `schema.prisma`:

```prisma
generator pzgPro {
  provider = "node ./node_modules/prisma-zod-generator/lib/cli/pzg-pro.js"
  output = "./generated/pro"
  enablePerformance = true
}
```

Then run:

```bash
prisma generate
```

### Generated Files

```
generated/
  pro/
    performance/
      streaming.ts           # Streaming validators
      precompiled.ts         # Precompiled schemas for speed
```

## Basic Usage

```ts
import { validateStream } from '@/generated/performance/streaming'

const users = Array.from({ length: 100_000 }, (_, i) => ({
  email: `user${i}@example.com`,
  name: `User ${i}`,
}))

const result = await validateStream(users, {
  chunkSize: 1000,         // Process 1000 records at a time
  maxConcurrency: 4,       // Use 4 parallel workers
  onProgress: (processed, total) => {
    console.log(`Progress: ${processed}/${total}`)
  },
  onError: (error, index) => {
    console.warn(`Invalid record at index ${index}:`, error)
  }
})

console.log(`Valid: ${result.valid.length}`)
console.log(`Invalid: ${result.invalid.length}`)
```

## Example: CSV Validation

```ts
import fs from 'fs'
import csv from 'csv-parser'
import { validateStream } from '@/generated/performance/streaming'

async function validateCSV(filePath: string) {
  const records: any[] = []

  // Read CSV
  await new Promise((resolve, reject) => {
    fs.createReadStream(filePath)
      .pipe(csv())
      .on('data', (row) => records.push(row))
      .on('end', resolve)
      .on('error', reject)
  })

  // Validate with streaming
  const result = await validateStream(records, {
    chunkSize: 1000,
    onProgress: (processed, total) => {
      console.log(`Validated ${processed}/${total} records`)
    }
  })

  return result
}
```

## See Also

- [Data Factories](./factories.md) - Generate large test datasets
- [API Docs Pack](./api-docs.md) - Test performance with mock server

# Policies & Redaction

> **Available in:** Professional, Business, Enterprise tiers

PII-safe logging and response redaction driven by annotations in your Prisma schema. Automatically mask sensitive data in logs, API responses, and error tracking.

## Why Use Policies & Redaction

**Problem**: Sensitive data leaks everywhere:

- PII (emails, phone numbers, SSNs) exposed in application logs
- Passwords and tokens accidentally logged to monitoring services
- Sensitive fields returned in API responses to unauthorized users
- Manual redaction is error-prone and inconsistent

**Solution**: Annotate sensitive fields in your Prisma schema once, then automatically redact them everywhere.

### Benefits

- **Schema-Driven**: Define policies once in Prisma schema
- **Auto Redaction**: Works with all logging libraries
- **Compliance Ready**: GDPR, HIPAA, PCI-DSS compliant logging
- **Zero Leaks**: Redact before data leaves your application

## Prerequisites

```bash
# Core dependencies
pnpm add @prisma/client zod

# For error tracking integration (optional)
pnpm add @sentry/node

# PZG Pro license required
```

## Generate

Add to your `schema.prisma`:

```prisma
generator pzgPro {
  provider = "node ./node_modules/prisma-zod-generator/lib/cli/pzg-pro.js"
  output = "./generated/pro"
  enablePolicies = true
}
```

Then run:

```bash
prisma generate
```

### Generated Files

```
generated/
  pro/
    policies/
      safe-crud/
        user.ts            # User safe CRUD operations
        post.ts            # Post safe CRUD operations
      redaction/
        user.ts            # User PII redaction middleware
        post.ts            # Post PII redaction middleware
      dto/
        user.ts            # User DTO schemas
        post.ts            # Post DTO schemas
      index.ts             # Exports and factory functions
```

## Schema Annotations

Annotate fields in your Prisma schema:

```prisma
model User {
  id       Int     @id @default(autoincrement())
  
  /// @pii email redact:logs
  /// @policy read:role in ["admin"]
  email    String  @unique
  
  /// @pii phone redact:logs
  phone    String?
  
  /// @sensitive redact:logs
  password String
  
  name     String?
}
```

## Basic Usage

### Safe CRUD Operations

```ts
import { createSafeUserOperations } from '@/generated/pro/policies'
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

// Create safe CRUD with policy context
const userOps = createSafeUserOperations(prisma, {
  userId: 'current-user-id',
  role: 'user'
})

// Automatically applies read policies
const users = await userOps.findMany()

// Automatically injects userId/tenantId on create
const newUser = await userOps.create({}, {
  data: { name: 'John', email: 'john@example.com' }
})
```

### PII Redaction

```ts
import { UserRedactor } from '@/generated/pro/policies/redaction/user'

const redactor = new UserRedactor({ redactLogs: true })

// Redact sensitive fields
const safeUser = redactor.redact(user, 'api')
// Result: { email: 's***@example.com', phone: '***-***-1234' }

// Express middleware
import { createUserRedactionMiddleware } from '@/generated/pro/policies/redaction/user'

app.use(createUserRedactionMiddleware())
const sentryTransport = createRedactedSentryTransport()
```

## Integration Examples

### Express API

```ts
import express from 'express'
import { redactionMiddleware } from '@/generated/pro/policies/redaction'

const app = express()

// Apply redaction middleware
app.use(redactionMiddleware())

app.get('/users/:id', async (req, res) => {
  const user = await prisma.user.findUnique({
    where: { id: parseInt(req.params.id) }
  })
  
  // Response automatically redacts PII fields
  res.json(user)
})
```

### Next.js API Routes

```ts
// Wrap ctx.body before send using redactPII(ctx.body) for Koa
// Custom interceptor calling redactPII(data) in map() for NestJS
```

## Browser Note

The generated helper uses Node `crypto`. In the browser, either polyfill (`crypto.subtle`) or use a minimal email-masking helper.

## See Also

- [Multi-Tenant Kit](./multi-tenant.md) - Tenant isolation with policy enforcement
- [PostgreSQL RLS](./postgres-rls.md) - Database-level row security

# PostgreSQL RLS

> **Available in:** Professional, Business, Enterprise tiers

Database-level row security with PostgreSQL Row-Level Security (RLS). Automatically enforce data isolation at the database layer with generated helpers, policies, and migrations.

## Why Use PostgreSQL RLS

**Problem**: Application-level security is fragile:

- Easy to forget WHERE clauses that filter by tenant/user
- Security bugs from missing filters in queries
- Complex authorization logic scattered across codebase
- No defense-in-depth at database level

**Solution**: Leverage PostgreSQL's built-in Row-Level Security to enforce data isolation at the database layer.

### Benefits

- **Database-Level Security**: Enforced at PostgreSQL layer, not application
- **Defense in Depth**: Additional security layer below Prisma
- **Auto Filtering**: Queries automatically scoped to user/tenant context
- **Developer Proof**: Impossible to bypass via code mistakes

## Prerequisites

```bash
# PostgreSQL database required
# Ensure your DATABASE_URL uses PostgreSQL

# Core dependencies
pnpm add @prisma/client

# PZG Pro license required
```

## Generate

Add to your `schema.prisma`:

```prisma
generator pzgPro {
  provider = "node ./node_modules/prisma-zod-generator/lib/cli/pzg-pro.js"
  output = "./generated/pro"
  enablePostgresRLS = true
}
```

Then run:

```bash
prisma generate
```

### Generated Files

```
generated/
  pro/
    postgres-rls/
      rls-helper.ts       # RLS context management
      migration.sql       # Database setup migration
      policies.sql        # Example RLS policies
```

## Basic Usage

```ts
import { PrismaClient } from '@prisma/client'
import { createRLSHelper } from '@/generated/pro/postgres-rls/rls-helper'

const prisma = new PrismaClient()
const rls = createRLSHelper(prisma)

// Set context before queries
await rls.withContext(
  {
    userId: 'user-123',
    tenantId: 'tenant-456',
    roles: ['admin']
  },
  async () => {
    // All queries in this block automatically filtered by RLS
    const posts = await prisma.post.findMany()
    // Only returns posts where policies allow access
  }
)
```

### Prisma Middleware

```ts
prisma.$use(rls.createMiddleware())

// Now you can pass context via query params
await prisma.post.findMany({
  context: {
    userId: 'u1',
    tenantId: 't1'
  }
})
```

## Database Setup

Apply the generated migration to set up RLS helper functions:

```sql
-- From generated/postgres/rls/migration.sql
-- Helper functions:
-- - set_current_user_context(user_id, tenant_id, roles)
-- - clear_user_context()
-- - get_current_user_context()
```

See generated SQL files for:

- Example RLS policies
- Helper function definitions
- Migration scripts to adapt to your schema

## Integration

### Express Middleware

```ts
app.use(async (req, res, next) => {
  if (!req.user) {
    return res.status(401).json({ error: 'Unauthorized' })
  }

  await rls.setContext({
    userId: req.user.id,
    tenantId: req.user.tenantId,
    roles: req.user.roles
  })

  res.on('finish', async () => {
    await rls.clearContext()
  })

  next()
})
```

### Next.js API Routes

```ts
import { rls } from '@/lib/rls'

export default async function handler(req, res) {
  const session = await getSession(req, res)

  return rls.withContext(
    {
      userId: session.user.id,
      tenantId: session.user.tenantId,
      roles: session.user.roles
    },
    async () => {
      const posts = await prisma.post.findMany()
      res.json(posts)
    }
  )
}
```

## See Also

- [Multi-Tenant Kit](./multi-tenant.md) - Application-layer tenant isolation
- [Policies & Redaction](./policies.md) - Field-level access control

# SDK Publisher

> **Available in:** Professional, Business, Enterprise tiers

Auto-generate a fully-typed, production-ready TypeScript SDK from your Prisma schema. Publish as npm package with ESM + CJS support, automatic retries, timeouts, and request/response validation.

## Why Use SDK Publisher

**Problem**: Building API clients is tedious and error-prone:

- Manually writing fetch calls for every endpoint
- Duplicating types between backend and frontend
- No automatic retry logic or timeout handling
- Type safety lost across the network boundary
- SDK maintenance when API changes
- Supporting both ESM and CommonJS consumers

**Solution**: Auto-generate a production-grade SDK package with full TypeScript support, automatic validation, error handling, and dual module formats ready to publish to npm.

### Benefits

- **Type Safety**: Full TypeScript from database to API client
- **Auto Validation**: Zod schemas validate all requests/responses
- **Dual Format**: ESM + CJS bundles with .d.ts files
- **Production Ready**: Built-in retries, timeouts, error handling
- **Auto Methods**: Generated methods for all CRUD operations
- **Publishable**: npm-ready package with package.json and exports

## Prerequisites

```bash
# Core dependencies for SDK generation
pnpm add @prisma/client zod

# PZG Pro license required
```

## Generate

Add to your `schema.prisma`:

```prisma
generator pzgPro {
  provider = "node ./node_modules/prisma-zod-generator/lib/cli/pzg-pro.js"
  output = "./generated/pro"
  enableSDK = true
}
```

Then run:

```bash
prisma generate
```

### Generated Files

```
generated/
  pro/
    sdk/
      typescript/
        index.ts           # TypeScript SDK with APIClient class
      python/
        api_client.py      # Python SDK (optional)
```

The generator creates SDK clients with methods per resource:

- Methods for all models (`listUsers`, `createUser`, `getUser`, etc.)
- TypeScript types and interfaces
- Built-in authentication support
- Ready for npm publishing

## Basic Usage

```ts
import APIClient from '@your-org/api-sdk'

const client = new APIClient({
  baseUrl: 'http://127.0.0.1:3001',
  authToken: process.env.TOKEN,
  timeout: 10_000,
  retryAttempts: 3,
})

// All methods return { success, data?, error?, issues? }
const res = await client.listUsers({ page: '1', limit: '10' })
if (!res.success) {
  console.error(res.error)
  if (res.issues) {
    // Zod validation errors
    console.error(res.issues)
  }
} else {
  console.log(res.data)
}
```

### CRUD Operations

```ts
// Create
const createRes = await client.createUser({
  email: 'user@example.com',
  name: 'John Doe'
})

// Read single
const userRes = await client.getUser({ id: '123' })

// Update
const updateRes = await client.updateUser({
  id: '123',
  name: 'Jane Doe'
})

// Delete
const deleteRes = await client.deleteUser({ id: '123' })
```

## Error Handling

All methods return a consistent response format:

```ts
type APIResponse<T> =
  | { success: true; data: T }
  | { success: false; error: string; issues?: ZodIssue[] }
```

Example error handling:

```ts
const res = await client.createUser(userData)

if (!res.success) {
  if (res.issues) {
    // Zod validation failed
    res.issues.forEach(issue => {
      console.error(`${issue.path.join('.')}: ${issue.message}`)
    })
  } else {
    // Network or server error
    console.error(res.error)
  }
  return
}

// Success
console.log('Created user:', res.data)
```

## Retry & Timeout Behavior

- **Timeouts**: Use `AbortSignal.timeout(timeout)` to abort long requests
- **Retries**: Exponential backoff on network errors (configurable via `retryAttempts`)
- **Non-retriable**: Client errors (4xx) and validation errors are not retried

## Routes

The generated SDK defaults align with the API Docs mock server routes:

- `/api/users` - User endpoints
- `/api/posts` - Post endpoints
- Custom routes can be configured

## Publishing Your SDK

The generated package includes:

- `package.json` with proper ESM/CJS exports
- TypeScript declaration files
- Build configuration for dual module output

To publish:

```bash
cd generated/sdk
pnpm install
pnpm run build
npm publish
```

## See Also

- [API Docs Pack](./api-docs.md) - Generate OpenAPI specs and mock server
- [Server Actions Pack](./server-actions.md) - Next.js server-side validation
- [Contract Testing](./contracts.md) - Verify SDK matches backend contracts

# Server Actions Pack

> **Available in:** Starter, Professional, Business, Enterprise tiers

Utilities and templates for type-safe Next.js Server Actions validated by Zod schemas.

## Why Use Server Actions Pack

**Problem**: Server Actions need validation:

- Manual validation is repetitive
- Type safety lost between client/server
- Error handling inconsistent
- No standard response format

**Solution**: Generate validated Server Action stubs with automatic Zod validation and type-safe responses.

### Benefits

- **Type-Safe**: End-to-end TypeScript
- **Auto Validation**: Zod schemas applied automatically
- **Consistent Errors**: Standard error response format
- **Next.js Integration**: Works with `revalidatePath`, `redirect`, etc.

## Prerequisites

```bash
# Core dependencies
pnpm add react zod @prisma/client

# Optional: Next.js 13+ for full integration
pnpm add next

# PZG Pro license required
```

> **Note**: The generator avoids direct Next.js imports to prevent dependency issues. Next.js features like `revalidatePath()` and `redirect()` are commented out in generated code - uncomment them if using Next.js.

## Generate

Add to your `schema.prisma`:

```prisma
generator pzgPro {
  provider = "node ./node_modules/prisma-zod-generator/lib/cli/pzg-pro.js"
  output = "./generated/pro"
  enableServerActions = true
}
```

Then run:

```bash
prisma generate
```

### Generated Files

```
generated/
  pro/
    server-actions/
      actions/
        user.ts          # User CRUD server actions
        post.ts          # Post CRUD server actions
      hooks/
        useUser.ts       # React hooks for User actions
        usePost.ts       # React hooks for Post actions
      types/
        common.ts        # Shared types
        user.ts          # User-specific types
        post.ts          # Post-specific types
      utils/
        validation.ts    # Validation helpers
      prisma-client.ts   # Prisma client instance
      USAGE.md           # Usage guide
```

## Basic Usage

### Server Actions

Generated server actions in `actions/user.ts`:

```ts
// Auto-generated with Zod validation and error handling
export async function createUser(
  data: Prisma.UserCreateInput
): Promise<ServerActionResult<User>> {
  try {
    const user = await prisma.user.create({ data });
    // revalidatePath('/users'); // Uncomment to enable
    return { success: true, data: user };
  } catch (error) {
    return handleServerActionError(error, 'Failed to create user');
  }
}
```

### React Hooks

Use generated hooks in `hooks/useUser.ts`:

```tsx
'use client'

import { useCreateUser } from '@/generated/pro/server-actions'

export function CreateUserForm() {
  const { execute, isPending, error } = useCreateUser({
    onSuccess: (user) => console.log('Created:', user),
    redirect: '/users'
  });

  return (
    <form onSubmit={(e) => {
      e.preventDefault();
      execute({ name: 'John', email: 'john@example.com' });
    }}>
      <button type="submit" disabled={isPending}>
        {isPending ? 'Creating...' : 'Create User'}
      </button>
      {error && <p className="error">{error}</p>}
    </form>
  )
}
```

## Next.js Integration

Generated actions include commented hints for Next.js features:

```ts
// Uncomment these in your Next.js app:
// import { revalidatePath } from 'next/cache'
// import { redirect } from 'next/navigation'

export async function createUser(data: Prisma.UserCreateInput) {
  const user = await prisma.user.create({ data });
  // revalidatePath('/users'); // Uncomment to enable cache revalidation
  // redirect('/users');        // Uncomment to enable redirect
  return { success: true, data: user };
}
```

The hooks also support redirect via options:

```ts
const { execute } = useCreateUser({
  redirect: '/users' // Logs redirect request (implement navigation as needed)
});
```

## See Also

- [Form UX Pack](./forms.md) - Generate form components
- [SDK Publisher](./sdk.md) - Type-safe API client

# Integration Guides Overview

# Integration Guides

We’re consolidating integration content so the links here reflect what actually exists in the repository. Until dedicated guides ship, start with the patterns below and adapt them to your stack.

## ✅ Available Resources

- **Next.js / React usage**: Combine the [Server Actions Pack](../features/server-actions.md) and [Forms UX Pack](../features/forms.md) to scaffold full-stack flows quickly.
- **Policy enforcement**: Pair [Policies & Redaction](../features/policies.md) with [PostgreSQL RLS](../features/postgres-rls.md) for multi-tenant backends.
- **SDK + Docs**: Use [Client SDK Publisher](../features/sdk.md) alongside the [API Docs Pack](../features/api-docs.md) to expose stable partner APIs.

## 🗺️ Roadmap

Detailed framework- and platform-specific guides (Next.js App Router, tRPC, Vercel, Supabase, etc.) are in progress. Track progress or request a specific integration by opening an issue.

***

## 🚀 Getting Started

1. **Choose Your Stack**: Select the frameworks and tools you're using
2. **Follow Integration Guides**: Step-by-step setup instructions
3. **Configure Features**: Enable the PZG Pro features you need
4. **Test Integration**: Verify everything works correctly

## 📚 Need Help?

- **Documentation**: Complete guides for each integration
- **Community Support**: [Open an issue or discussion](https://github.com/omar-dulaimi/prisma-zod-generator/issues)
- **Examples Repository**: [See working examples](https://github.com/omar-dulaimi/pzg-examples)
- **Support**: DM [@omardulaimidev on X](https://x.com/omardulaimidev) for licensing or escalations

***

**Don't see your framework?** [Request an integration guide](https://github.com/omar-dulaimi/prisma-zod-generator/issues/new) or contribute one!

# Core Concepts

**Variants**: Parallel schema sets expressing different contexts.

| Variant | Intent                                     | Typical Fields             |
| ------- | ------------------------------------------ | -------------------------- |
| pure    | Canonical model snapshot (optionally lean) | All / minus excluded       |
| input   | Data accepted for create/update ops        | Often omits id, timestamps |
| result  | Data returned to callers                   | Usually full model         |

You can also define **array-based custom variants** with suffix, exclusions, and optional field transforms.

**Modes**:

- `full` – everything enabled by default.
- `minimal` – lean subset: restricts operations, disables select/include, prunes complex nested inputs.
- `custom` – you explicitly enable/disable.

**Filtering Layers** (highest precedence first):

1. `model.fields.include`
2. model variant excludes (`models[Model].variants.variant.excludeFields`)
3. legacy `model.fields.exclude`
4. global variant excludes (`globalExclusions.variant`)
5. global array excludes (legacy array form)

**Emission Controls**: `emit.enums`, `emit.objects`, `emit.crud`, `emit.pureModels`, `emit.variants`, `emit.results`—each can short‑circuit generation to reduce output.

**Heuristics**:

- `pureModelsOnlyMode`: pureModels + all variants disabled (custom mode) ⇒ only pure models emitted.
- `pureVariantOnlyMode`: pureModels + only pure variant enabled ⇒ skip CRUD/input/result scaffolding.

**Circular Dependency Resolution**: When `pureModelsIncludeRelations` is enabled, `pureModelsExcludeCircularRelations` can intelligently exclude problematic bidirectional relations to avoid TypeScript circular dependency errors while preserving foreign keys.

**Strict Mode Configuration**: Fine-grained control over when `.strict()` is applied to generated Zod schemas:

- **Global Control**: Configure strict mode for all schemas or specific schema types (operations, objects, variants)
- **Model-Level Overrides**: Set different strict mode behavior for specific models
- **Operation-Specific**: Control strict mode for individual operations (findMany, create, update, etc.)
- **Variant-Level**: Configure strict mode independently for pure, input, and result variants
- **Enum Handling**: Enums are inherently strict and don't support `.strict()` method
- **Backward Compatible**: Defaults to strict mode enabled everywhere for existing projects

See the [strict mode configuration page](/docs/config/strict-mode) for complete documentation and common patterns.

**Naming Customization** drives file & export shapes across all schema types:

- **Pure Models**: `naming.preset` + `naming.pureModel` overrides
- **CRUD Schemas**: `naming.schema` for operation file/export patterns (requires `{operation}` token to avoid collisions)
- **Input Objects**: `naming.input` for input type file/export patterns
- **Enums**: `naming.enum` for enum file/export patterns

See the [naming configuration page](/docs/config/naming) for complete documentation.

# Quick Start

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

## 1. Install

### Requirements

| Component  | Minimum | Recommended |
| ---------- | ------- | ----------- |
| Node.js    | 20.19.0 | 22.x        |
| Prisma     | 7.0.0   | Latest 7.x  |
| Zod        | 4.0.5   | Latest 4.x  |
| TypeScript | 5.4.0   | 5.9.x       |

<Tabs>
  <TabItem value="npm" label="npm">
    ```bash
    npm install prisma-zod-generator zod @prisma/client
    ```
  </TabItem>

  <TabItem value="yarn" label="yarn">
    ```bash
    yarn add prisma-zod-generator zod @prisma/client
    ```
  </TabItem>

  <TabItem value="pnpm" label="pnpm">
    ```bash
    pnpm add prisma-zod-generator zod @prisma/client
    ```
  </TabItem>
</Tabs>

## 2. Add generator to `schema.prisma`

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

generator zod {
  provider = "prisma-zod-generator"
  // optional output = "./prisma/generated" (JSON config can supply if omitted)
  // optional config = "./zod-generator.config.json" (relative to schema file)
}
```

:::info Config Path Resolution
Config file paths (e.g., `config = "./my-config.json"`) are resolved **relative to the Prisma schema file location**, not the project root. If your schema is at `prisma/schema.prisma`, then `config = "./my-config.json"` will look for the config file at `prisma/my-config.json`.
:::

## 3. (Optional) Create configuration file

Create `prisma/zod-generator.config.json` (next to your schema file):

```jsonc
{
  "mode": "full",
  "pureModels": true,
  "variants": {
    "pure": { "enabled": true },
    "input": { "enabled": true },
    "result": { "enabled": true },
  },
}
```

## 4. Generate

```bash
npx prisma generate
```

## 5. Consume

```ts
import { UserSchema, UserInputSchema } from './prisma/generated/schemas';
UserSchema.parse(data);
```

## Directory Layout (multi-file default)

```
prisma/generated/
  schemas/
    enums/
    objects/
    variants/
    index.ts
  models/
```

Single-file mode collapses to `schemas.ts` via config (`useMultipleFiles:false`).

## Next Steps

Explore PZG Pro feature packs (SDK, Forms, API Docs, RLS, Multi‑tenant, Performance, Factories, Guard, Contracts, Server Actions): [Pro Features](../features/overview.md).

# Prisma Zod Generator

**The most powerful Prisma generator for type-safe validation** - Generate Zod schemas, React forms, TypeScript SDKs, OpenAPI docs, and more directly from your Prisma schema.

## Core Features (Free & Open Source)

Generate production-ready Zod validation schemas from your Prisma models with full customization:

### Schema Generation

- **Multiple variants**: Pure models, input schemas, result schemas
- **Generation modes**: Minimal (lean), Full (everything), Custom (fine-tuned)
- **Field filtering**: Include/exclude specific fields with wildcard patterns
- **Custom naming**: Configure naming patterns for all schema types
- **Output layouts**: Single-file or multi-file organization

### Advanced Validation

- **@zod annotations**: Add inline validation rules in Prisma comments
- **Type coercion**: Handle Bytes, Decimal, DateTime, JSON types
- **Relation handling**: Smart defaults for nested objects
- **Aggregate support**: Count, min, max, avg, sum operations
- **Optional fields**: Configurable `.nullish()`, `.optional()`, or `.nullable()`

### Why Use Prisma Zod Generator?

✅ **Eliminate drift** - Your validation always matches your database schema
✅ **Type safety** - End-to-end TypeScript from database to API
✅ **Configurable** - From minimal lean schemas to full CRUD suites
✅ **Production ready** - Used by thousands of projects worldwide
✅ **Domain-specific** - Generate different schema bundles for different contexts

## Pro Features

Upgrade to Pro for production-ready feature packs that save weeks of development time:

### 🎨 Developer Experience ($69/year - Starter)

- **[Form UX Pack](../features/forms.md)** - Auto-generated React forms with validation
- **[Server Actions](../features/server-actions.md)** - Typed Next.js server actions

### 🔐 Security & Governance ($199/year - Professional)

- **[Policies & Redaction](../features/policies.md)** - PII masking, GDPR compliance
- **[Drift Guard](../features/guard.md)** - CI checks for breaking schema changes
- **[PostgreSQL RLS](../features/postgres-rls.md)** - Database-level row security
- **[Performance Pack](../features/performance.md)** - Stream validation for millions of records
- **[SDK Publisher](../features/sdk.md)** - Generate typed API clients

### 🏗️ Platform & Scale ($599/year - Business)

- **[Contract Testing](../features/contracts.md)** - Consumer-driven Pact.js tests
- **[API Docs Pack](../features/api-docs.md)** - OpenAPI specs + mock server
- **[Data Factories](../features/factories.md)** - Realistic test data generation

### 🚀 Enterprise ($$$$ - Custom)

- **[Multi-Tenant Kit](../features/multi-tenant.md)** - Enterprise SaaS isolation
- **Quarterly Roadmap Reviews** - Strategic planning with the core team
- **Co-developed Feature Packs** - Build bespoke integrations together
- **White-Glove Onboarding** - Rollout playbooks and migration guidance

[View all Pro features →](../features/overview.md)

## Getting Started

```bash
# Install generator
pnpm add -D prisma-zod-generator

# Configure in schema.prisma
generator zod {
  provider = "prisma-zod-generator"
  output   = "./generated/zod"
}

# Generate schemas
pnpm prisma generate
```

[Read the full documentation →](../intro/quick-start.md)

### Using Pro Features

After purchasing a Pro tier:

1. You'll receive license key and setup instructions
2. Follow the provided installation guide
3. Use `pzg-pro` commands to generate feature packs

See [Pro Features Overview](../features/overview.md) for details.

# Performance & Build Tips

Strategies to reduce generation time and bundle size.

## Use Minimal Mode for Fast Iteration

`mode: "minimal"` prunes deep nested inputs and disables select/include.

## Targeted Model Generation

Restrict models via `models: { ModelName: {...} }` to skip unused ones.

## Disable Unused Categories

Turn off `emit.crud`, `emit.results`, or `emit.variants` when not needed.

## Single File for Deployment

`useMultipleFiles: false` produces one file—ideal for serverless bundling.

## Lean Pure Models

`pureModelsLean: true` + exclude heavy relations globally.

## Avoid Enum Explosion

Exclude enums or limit variants if you have large enum sets.

## CI Parallelization

Combine with `VITEST_PARALLEL=true` tests to overlap generation and testing in pipelines.

# Object & CRUD Generation

Steps:

1. Prisma DMMF loaded via `getDMMF`.
2. Input object & model operation lists cloned.
3. Hidden models/fields resolved from model comments.
4. Missing input object types added (legacy support) before filtering.
5. Object schemas generated if `emit.objects` and not pure-only heuristics; each object pre-filtered with `filterFields`.
6. CRUD operation schemas assembled (model args, aggregate support) if `emit.crud`.
7. Objects index synthesized (for integration consistency).

`isObjectSchemaEnabled` checks model enablement + required operations + minimal mode pruning heuristics.

Aggregate result schemas produced via `generateResultSchemas` (if results not forcibly disabled).

# Pure Model Schemas

Activated when `pureModels` true (implicitly in minimal mode) or `emit.pureModels`.

Flow:

- Enabled models filtered.
- Per-model exclusions combined (global pure exclusions + legacy + variant pure excludes).
- Naming preset resolved → fileName, export names, optional legacy aliases.
- Relation imports & enum imports normalized for custom patterns.
- If single-file mode: still written individually, then bundled.

Lean vs relations:

- `pureModelsLean` keeps scalar + enum fields (default true).
- `pureModelsIncludeRelations` can include relation lazy refs.
- `pureModelsExcludeCircularRelations` excludes problematic circular relations when `pureModelsIncludeRelations` is true.

Bytes default: base64 string; set `complexTypes.bytes.useBase64=false` (in config) for Uint8Array.

# Single File Mode

Enable with `useMultipleFiles: false`.

Mechanics:

- Initializes aggregator with resolved bundle path.
- Writes all schema content through in-memory collection.
- After generation, flushes aggregator and deletes sibling entries (keeps bundle only).
- Adjusts Prisma Client import to relative path if custom client output.
- Suppresses variant emission to avoid directory clutter.

Use when embedding schemas directly into application packages or publishing a lightweight distribution.

# Special Type Mapping

| Prisma   | Zod (I/O)                          | Pure Models Default | Notes                                                     |
| -------- | ---------------------------------- | ------------------- | --------------------------------------------------------- |
| String   | z.string()                         | same                | optional + .nullable() when optional string input variant |
| Int      | z.number().int()                   | same                |                                                           |
| Float    | z.number()                         | same                |                                                           |
| Boolean  | z.boolean()                        | same                |                                                           |
| DateTime | z.date()                           | same                | (strategy: date)                                          |
| Json     | z.unknown() + optional refinements | same                | Optional depth/length validations                         |
| Bytes    | z.instanceof(Uint8Array)           | z.string() (base64) | Override to Uint8Array by `useBase64:false`               |
| BigInt   | z.bigint()                         | same                |                                                           |
| Decimal  | z.instanceof(Prisma.Decimal)       | same                | Full Decimal.js support (configurable via `decimalMode`)  |
| Enums    | \<Enum>Schema                      | \<Enum>Schema       | Generated enum schemas                                    |

**Bytes**: adds size constraints & base64 regex or length refinements depending on representation.

**JSON**: Can enforce serializability, depth, and length; adds descriptive comments in generated file.

## Decimal Type Support

The `Decimal` type in Prisma is mapped to Zod schemas based on the `decimalMode` configuration option. This feature provides full compatibility with `zod-prisma-types` for seamless migration.

### Configuration Options

Configure decimal handling via the `decimalMode` option in your config file:

```json
{
  "decimalMode": "decimal" // "decimal" | "number" | "string"
}
```

### Modes

#### `decimal` (Default, Recommended)

Full `Decimal.js` support matching `zod-prisma-types` implementation:

- **Pure Models**: `z.instanceof(Prisma.Decimal)` with descriptive error messages
- **Input Types**: Union of `number | string | Prisma.Decimal | Decimal` (if decimal.js installed) with runtime validation
- **Imports**: Automatically imports `Prisma` from `@prisma/client` (non-type import for instanceof checks)

**Example Output:**

```typescript
// Pure model schema
export const ProductSchema = z.object({
  id: z.number().int(),
  price: z.instanceof(Prisma.Decimal, {
    message: "Field 'price' must be a Decimal. Location: ['Models', 'Product']",
  }),
});
```

#### `number`

Legacy mode for backward compatibility:

- Maps `Decimal` fields to `z.number()`
- **Warning**: May lose precision for large decimal values
- Use when you don't need exact decimal precision

#### `string`

String-based validation with regex patterns:

- Maps `Decimal` fields to `z.string()` with decimal format validation
- Includes precision-aware regex patterns
- Preserves decimal precision as string representation

### Migration from zod-prisma-types

If you're migrating from `zod-prisma-types`, use `decimalMode: "decimal"` (the default) for drop-in compatibility. The generator will:

1. Generate `z.instanceof(Prisma.Decimal)` for model schemas
2. Create proper import statements for `Prisma`
3. Match the validation patterns from `zod-prisma-types`

### Decimal.js Installation

While `decimal.js` is not required, installing it provides enhanced type safety:

```bash
pnpm add decimal.js
```

When `decimal.js` is installed, input schemas will also accept `Decimal` instances in the validation union.

# @zod Comment Annotations

Use triple-slash Prisma doc comments with `@zod` to append validations.

```prisma
model User {
  id    String @id @default(cuid())
  /// @zod.email().min(5)
  email String @unique
}
```

Result:

```ts
export const UserSchema = z
  .object({
    email: z.string().email().min(5),
    // ...
  })
  .strict();
```

Annotations are concatenated after base type; unsafe expressions are not executed (string append model). Keep rules pure.

## Complete Feature Reference

### String Validations

#### Length & Content Validation

```prisma
model StringValidation {
  id       String @id @default(cuid())
  /// @zod.min(2, "Too short")
  name     String
  /// @zod.max(100)
  title    String
  /// @zod.length(10)
  code     String
  /// @zod.includes("@")
  email    String
  /// @zod.startsWith("https://")
  website  String
  /// @zod.endsWith(".com")
  domain   String
  /// @zod.regex(/^[A-Z]+$/, "Must be uppercase")
  acronym  String
}
```

#### String Transformation

```prisma
model StringTransform {
  id         String @id @default(cuid())
  /// @zod.trim()
  cleaned    String
  /// @zod.toLowerCase()
  slug       String
  /// @zod.toUpperCase()
  code       String
  /// @zod.uppercase()
  acronym    String
  /// @zod.lowercase()
  text       String
  /// @zod.normalize()
  normalized String
}
```

#### Standard Format Validation

```prisma
model StandardFormats {
  id        String @id @default(cuid())
  /// @zod.email("Invalid email format")
  email     String @unique
  /// @zod.url()
  website   String?
  /// @zod.uuid()
  reference String
  /// @zod.datetime()
  timestamp String
  /// @zod.ip()
  ipAddress String
  /// @zod.cidr()
  network   String
  /// @zod.date()
  dateStr   String
  /// @zod.time()
  timeStr   String
  /// @zod.duration()
  period    String
}
```

### Zod v4 String Format Methods

The generator automatically detects your Zod version and uses optimized base types in v4.

#### Network & URL Formats

```prisma
model NetworkFormats {
  id       String @id @default(cuid())
  /// @zod.httpUrl()
  apiUrl   String
  /// @zod.hostname()
  server   String
  /// @zod.ipv4()
  ipAddress String
  /// @zod.ipv6()
  ipv6Addr String?
  /// @zod.cidrv4()
  subnet   String
  /// @zod.cidrv6()
  subnet6  String?
}
```

Generated schema (Zod v4):

```ts
export const NetworkFormatsCreateInputSchema = z.object({
  apiUrl: z.httpUrl(),      // Base type in v4
  server: z.hostname(),     // Base type in v4
  ipAddress: z.ipv4(),      // Base type in v4
  ipv6Addr: z.ipv6().optional(),
  subnet: z.cidrv4(),
  subnet6: z.cidrv6().optional(),
});
```

#### Identifier Formats

```prisma
model Identifiers {
  id       String @id @default(cuid())
  /// @zod.guid()
  guid     String
  /// @zod.nanoid()
  nanoid   String
  /// @zod.cuid()
  cuid     String
  /// @zod.cuid2()
  cuid2    String
  /// @zod.ulid()
  ulid     String
}
```

Generated schema (Zod v4):

```ts
export const IdentifiersCreateInputSchema = z.object({
  guid: z.guid(),       // Base type in v4
  nanoid: z.nanoid(),   // Base type in v4
  cuid: z.cuid(),       // Base type in v4
  cuid2: z.cuid2(),     // Base type in v4
  ulid: z.ulid(),       // Base type in v4
});
```

#### Encoding & Character Formats

```prisma
model EncodingData {
  id        String @id @default(cuid())
  /// @zod.base64()
  base64    String
  /// @zod.base64url()
  base64url String
  /// @zod.hex()
  hex       String
  /// @zod.emoji()
  reaction  String
}
```

Generated schema (Zod v4):

```ts
export const EncodingDataCreateInputSchema = z.object({
  base64: z.base64(),       // Base type in v4
  base64url: z.base64url(), // Base type in v4
  hex: z.hex(),             // Base type in v4
  reaction: z.emoji(),      // Base type in v4
});
```

#### Security & Crypto Formats

```prisma
model SecurityData {
  id        String @id @default(cuid())
  /// @zod.jwt()
  token     String?
  /// @zod.hash("sha256")
  checksum  String
}
```

Generated schema (Zod v4):

```ts
export const SecurityDataCreateInputSchema = z.object({
  token: z.jwt().optional(),        // Base type in v4
  checksum: z.hash("sha256"),       // Base type with parameter
});
```

#### ISO Date/Time Formats

```prisma
model ISOFormats {
  id         String @id @default(cuid())
  /// @zod.isoDate()
  date       String
  /// @zod.isoTime()
  time       String
  /// @zod.isoDatetime()
  datetime   String
  /// @zod.isoDuration()
  duration   String
}
```

Generated schema (Zod v4):

```ts
export const ISOFormatsCreateInputSchema = z.object({
  date: z.iso.date(),         // ISO methods use z.iso namespace
  time: z.iso.time(),
  datetime: z.iso.datetime(),
  duration: z.iso.duration(),
});
```

### Number Validations

```prisma
model NumberValidation {
  id       String @id @default(cuid())
  /// @zod.min(0, "Cannot be negative")
  score    Int
  /// @zod.max(100)
  percent  Int
  /// @zod.gt(0, "Must be greater than 0")
  revenue  Float
  /// @zod.gte(0, "Cannot be negative")
  assets   Float
  /// @zod.lt(100, "Must be less than 100")
  discount Float
  /// @zod.lte(100, "Cannot exceed 100")
  capacity Float
  /// @zod.step(0.01, "Must be in 0.01 increments")
  price    Float
  /// @zod.positive("Must be positive")
  amount   Float
  /// @zod.negative()
  debt     Float?
  /// @zod.nonnegative()
  balance  Float
  /// @zod.nonpositive()
  loss     Float?
  /// @zod.int()
  whole    Float
  /// @zod.finite()
  measured Float
  /// @zod.safe()
  counter  Int
  /// @zod.multipleOf(5, "Must be multiple of 5")
  rating   Int
}
```

Generated schema:

```ts
export const NumberValidationCreateInputSchema = z.object({
  score: z.number().int().min(0, "Cannot be negative"),
  percent: z.number().int().max(100),
  revenue: z.number().gt(0, "Must be greater than 0"),
  assets: z.number().gte(0, "Cannot be negative"),
  discount: z.number().lt(100, "Must be less than 100"),
  capacity: z.number().lte(100, "Cannot exceed 100"),
  price: z.number().multipleOf(0.01, "Must be in 0.01 increments"),
  amount: z.number().positive("Must be positive"),
  debt: z.number().negative().optional(),
  balance: z.number().nonnegative(),
  loss: z.number().nonpositive().optional(),
  whole: z.number().int(),
  measured: z.number().finite(),
  counter: z.number().int().safe(),
  rating: z.number().int().multipleOf(5, "Must be multiple of 5"),
});
```

### Array Validations

```prisma
model ArrayValidation {
  id      String   @id @default(cuid())
  /// @zod.min(1, "At least one item required")
  tags    String[]
  /// @zod.max(10)
  items   String[]
  /// @zod.length(3)
  coords  Float[]
  /// @zod.nonempty()
  colors  String[]
  /// @zod.nullable()
  options String[]?
}
```

Generated schema:

```ts
export const ArrayValidationCreateInputSchema = z.object({
  tags: z.string().array().min(1, "At least one item required"),
  items: z.string().array().max(10),
  coords: z.number().array().length(3),
  colors: z.string().array().nonempty(),
  options: z.string().array().nullable().optional(),
});
```

### Date Validations

```prisma
model DateValidation {
  id        String   @id @default(cuid())
  /// @zod.min(new Date('2020-01-01'))
  startDate DateTime
  /// @zod.max(new Date('2030-12-31'))
  endDate   DateTime
}
```

### Field Modifiers

```prisma
model FieldModifiers {
  id          String @id @default(cuid())
  /// @zod.optional()
  description String
  /// @zod.nullable()
  notes       String?
  /// @zod.nullish()
  metadata    String?
  /// @zod.default("active")
  status      String
}
```

### Advanced Modifiers

```prisma
model AdvancedModifiers {
  id         String @id @default(cuid())
  /// @zod.catch("fallback")
  safeData   String
  /// @zod.pipe(z.string().transform(s => s.toUpperCase()))
  processed  String
  /// @zod.brand<"UserId">()
  userId     String
  /// @zod.readonly()
  immutable  String
}
```

Generated schema:

```ts
export const AdvancedModifiersCreateInputSchema = z.object({
  safeData: z.string().catch("fallback"),
  processed: z.string().pipe(z.string().transform(s => s.toUpperCase())),
  userId: z.string().brand<"UserId">(),
  immutable: z.string().readonly(),
});
```

### Custom Validation & Transformation

```prisma
model CustomValidation {
  id       String @id @default(cuid())
  /// @zod.refine((val) => val.length > 0, { message: "Cannot be empty" })
  content  String
  /// @zod.transform((val) => val.trim().toLowerCase())
  slug     String
  /// @zod.enum(["admin", "user", "guest"])
  role     String
}
```

### Special Field Types

```prisma
model SpecialTypes {
  id       String @id @default(cuid())
  /// @zod.json()
  metadata Json
  /// @zod.custom({ "name": "John", "age": 30, "active": true })
  profile  Json
}
```

## External Validators with `@zod.import`

Bring in runtime helpers directly from doc comments when you need logic that lives outside the generated file.

```prisma
model User {
  id    String @id @default(cuid())
  /// @zod.import(["import { isEmail } from '../validators/email'"])
  /// @zod.custom.use(z.string().refine((val) => isEmail(val), { message: 'Invalid email' }))
  email String @unique
}
```

Generated schema (Pure Variant excerpt):

```ts
import { isEmail } from '../validators/email';

export const UserSchema = z
  .object({
    email: z.string().refine((val) => isEmail(val), {
      message: 'Invalid email',
    }),
    // ...
  })
  .strict();
```

### Import Features

- Provide one or more complete import statements inside the array
- Relative paths are kept intact and rewritten per output directory
- Imports must produce runtime values. Type-only specifiers are detected and omitted
- Field-level imports are merged with model-level imports
- Duplicate statements are emitted once

### Model-level imports

Model-level imports can also supply chained refinements:

```prisma
/// @zod.import(["import { assertCompanyDomain } from '../validators/domain'"]).refine(assertCompanyDomain)
model Organisation {
  id    String @id @default(cuid())
  email String @unique
}
```

## Custom Inline Override (@zod.custom.use)

Replace an entire field schema inline:

```prisma
model AiChat {
  id        String @id @default(cuid())
  /// @zod.custom.use(z.array(z.object({ role: z.enum(['user','assistant','system']), parts: z.array(z.object({ type: z.enum(['text','image']), text: z.string() })) })))
  messages  Json   @default("[]")
}
```

Result (excerpt):

```ts
messages: z.array(
  z.object({
    role: z.enum(['user', 'assistant', 'system']),
    parts: z.array(z.object({ type: z.enum(['text', 'image']), text: z.string() })),
  }),
).default('[]');
```

This short-circuits other annotations for that field.

## Custom Object Schema (@zod.custom)

For JSON fields, use `@zod.custom()` to define structured object schemas using JavaScript object literals:

```prisma
model User {
  id String @id @default(cuid())

  /// @zod.custom({ "title": "User Profile", "description": "User details", "isActive": true })
  profile Json

  /// @zod.custom({ "settings": { "theme": "dark", "notifications": true }, "preferences": ["email", "sms"] })
  metadata Json
}
```

Result:

```ts
// Creates type-safe object schemas
profile: z.union([JsonNullValueInputSchema, z.object({
  title: z.string(),
  description: z.string(),
  isActive: z.boolean()
})]).optional(),

metadata: z.union([JsonNullValueInputSchema, z.object({
  settings: z.object({
    theme: z.string(),
    notifications: z.boolean()
  }),
  preferences: z.array(z.string())
})]).optional()
```

### Supported Value Types in @zod.custom()

- **Strings** → `z.string()`
- **Numbers** → `z.number().int()` or `z.number()`
- **Booleans** → `z.boolean()`
- **Arrays** → `z.array(T)` (inferred from first element)
- **Nested Objects** → `z.object({...})`
- **null** → `z.null()`

## Chaining Support

All methods can be chained together:

```prisma
model ChainedValidations {
  id       String @id @default(cuid())
  /// @zod.email().max(100).toLowerCase()
  email    String @unique
  /// @zod.nanoid().min(21)
  publicId String
  /// @zod.min(1).max(50).trim().regex(/^[A-Za-z\s]+$/)
  name     String
  /// @zod.positive().int().multipleOf(5)
  score    Int
}
```

Generated schema (Zod v4):

```ts
export const ChainedValidationsCreateInputSchema = z.object({
  email: z.email().max(100).toLowerCase(),
  publicId: z.nanoid().min(21),
  name: z.string().min(1).max(50).trim().regex(/^[A-Za-z\s]+$/),
  score: z.number().int().positive().multipleOf(5),
});
```

## Native Type Max Length Validation

The generator automatically extracts max length constraints from database native types and applies them as Zod `.max()` validations.

### Supported Native Types

| Database       | Native Types                                       | Example             | Generated Validation  |
| -------------- | -------------------------------------------------- | ------------------- | --------------------- |
| **PostgreSQL** | `VarChar(n)`, `Char(n)`                            | `@db.VarChar(255)`  | `z.string().max(255)` |
| **MySQL**      | `VarChar(n)`, `Char(n)`                            | `@db.VarChar(100)`  | `z.string().max(100)` |
| **SQL Server** | `VarChar(n)`, `Char(n)`, `NVarChar(n)`, `NChar(n)` | `@db.NVarChar(500)` | `z.string().max(500)` |
| **SQLite**     | No length constraints                              | -                   | No auto-validation    |
| **MongoDB**    | `ObjectId`                                         | `@db.ObjectId`      | `z.string().max(24)`  |

### Basic Usage

```prisma
model User {
  id          String  @id @default(cuid())
  email       String  @db.VarChar(320)  // → z.string().max(320)
  displayName String? @db.VarChar(100)  // → z.string().max(100).optional()
  bio         String? @db.Char(500)     // → z.string().max(500).optional()
}
```

Generated schema:

```ts
export const UserCreateInputSchema = z.object({
  email: z.string().max(320),
  displayName: z.string().max(100).optional(),
  bio: z.string().max(500).optional(),
});
```

### Conflict Resolution with @zod Comments

When both native types and `@zod.max()` exist, the **more restrictive** constraint is used:

```prisma
model Product {
  id          String  @id @default(cuid())

  // Native type wins (more restrictive)
  shortName   String  @db.VarChar(50) /// @zod.max(100)

  // @zod wins (more restrictive)
  description String? @db.VarChar(1000) /// @zod.max(500)

  // Only native constraint
  category    String  @db.VarChar(80)

  // Only @zod constraint
  tags        String? /// @zod.max(200)
}
```

Generated result:

```ts
export const ProductCreateInputSchema = z.object({
  shortName: z.string().max(50), // Native type (50) < @zod (100)
  description: z.string().max(500).optional(), // @zod (500) < Native (1000)
  category: z.string().max(80), // Only native constraint
  tags: z.string().max(200).optional(), // Only @zod constraint
});
```

### Complex Validations

Native constraints work alongside other `@zod` validations:

```prisma
model Account {
  id       String @id @default(cuid())
  /// @zod.email().toLowerCase()
  email    String @unique @db.VarChar(320)
  /// @zod.min(8).regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/)
  password String @db.VarChar(255)
}
```

Generated schema:

```ts
export const AccountCreateInputSchema = z.object({
  email: z.string().max(320).email().toLowerCase(),
  password: z
    .string()
    .max(255)
    .min(8)
    .regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/),
});
```

### Array Support

Native constraints are applied to array elements:

```prisma
model Tags {
  id    String   @id @default(cuid())
  names String[] @db.VarChar(50)  // Each string max 50 chars
}
```

Generated schema:

```ts
export const TagsCreateInputSchema = z.object({
  names: z.string().max(50).array(),
});
```

## Version Compatibility

The generator automatically detects your Zod version:

- **Zod v4**: Uses optimized base types like `z.email()`, `z.nanoid()`
- **Zod v3**: Falls back to chaining methods like `z.string().email()` where supported, or `z.string()` for unsupported methods

## Complete Method Reference

### String Methods

| Method               | Parameters                      | Description                        |
| -------------------- | ------------------------------- | ---------------------------------- |
| `@zod.min(n)`        | number, optional error message  | Minimum string length              |
| `@zod.max(n)`        | number, optional error message  | Maximum string length              |
| `@zod.length(n)`     | number, optional error message  | Exact string length                |
| `@zod.email()`       | optional error message/config   | Email validation                   |
| `@zod.url()`         | optional error message/config   | URL validation                     |
| `@zod.uuid()`        | optional error message/config   | UUID validation                    |
| `@zod.regex()`       | pattern, optional error message | Regular expression validation      |
| `@zod.includes()`    | substring                       | String must contain substring      |
| `@zod.startsWith()`  | prefix                          | String must start with prefix      |
| `@zod.endsWith()`    | suffix                          | String must end with suffix        |
| `@zod.trim()`        | none                            | Remove leading/trailing whitespace |
| `@zod.toLowerCase()` | none                            | Convert to lowercase               |
| `@zod.toUpperCase()` | none                            | Convert to uppercase               |
| `@zod.datetime()`    | optional error message/config   | ISO datetime validation            |

### Zod v4 String Format Methods

| Method               | Description               | Zod v4 Output      | Zod v3 Fallback |
| -------------------- | ------------------------- | ------------------ | --------------- |
| `@zod.httpUrl()`     | HTTP/HTTPS URL validation | `z.httpUrl()`      | `z.string()`    |
| `@zod.hostname()`    | Hostname validation       | `z.hostname()`     | `z.string()`    |
| `@zod.nanoid()`      | Nanoid validation         | `z.nanoid()`       | `z.string()`    |
| `@zod.cuid()`        | CUID validation           | `z.cuid()`         | `z.string()`    |
| `@zod.cuid2()`       | CUID v2 validation        | `z.cuid2()`        | `z.string()`    |
| `@zod.ulid()`        | ULID validation           | `z.ulid()`         | `z.string()`    |
| `@zod.base64()`      | Base64 validation         | `z.base64()`       | `z.string()`    |
| `@zod.base64url()`   | Base64URL validation      | `z.base64url()`    | `z.string()`    |
| `@zod.hex()`         | Hexadecimal validation    | `z.hex()`          | `z.string()`    |
| `@zod.jwt()`         | JWT token validation      | `z.jwt()`          | `z.string()`    |
| `@zod.hash(algo)`    | Hash validation           | `z.hash("sha256")` | `z.string()`    |
| `@zod.ipv4()`        | IPv4 address validation   | `z.ipv4()`         | `z.string()`    |
| `@zod.ipv6()`        | IPv6 address validation   | `z.ipv6()`         | `z.string()`    |
| `@zod.cidrv4()`      | CIDR v4 validation        | `z.cidrv4()`       | `z.string()`    |
| `@zod.cidrv6()`      | CIDR v6 validation        | `z.cidrv6()`       | `z.string()`    |
| `@zod.emoji()`       | Single emoji validation   | `z.emoji()`        | `z.string()`    |
| `@zod.isoDate()`     | ISO date validation       | `z.iso.date()`     | `z.string()`    |
| `@zod.isoTime()`     | ISO time validation       | `z.iso.time()`     | `z.string()`    |
| `@zod.isoDatetime()` | ISO datetime validation   | `z.iso.datetime()` | `z.string()`    |
| `@zod.isoDuration()` | ISO duration validation   | `z.iso.duration()` | `z.string()`    |

### Number Methods

| Method               | Parameters                     | Field Types        | Description               |
| -------------------- | ------------------------------ | ------------------ | ------------------------- |
| `@zod.min(n)`        | number, optional error message | Int, Float, BigInt | Minimum value             |
| `@zod.max(n)`        | number, optional error message | Int, Float, BigInt | Maximum value             |
| `@zod.int()`         | none                           | Int, Float         | Integer validation        |
| `@zod.positive()`    | optional error message         | Int, Float, BigInt | Positive number (> 0)     |
| `@zod.negative()`    | none                           | Int, Float, BigInt | Negative number (\< 0)    |
| `@zod.nonnegative()` | none                           | Int, Float, BigInt | Non-negative number (≥ 0) |
| `@zod.nonpositive()` | none                           | Int, Float, BigInt | Non-positive number (≤ 0) |
| `@zod.finite()`      | none                           | Float              | Finite number             |
| `@zod.safe()`        | none                           | Int, Float         | Safe integer              |
| `@zod.multipleOf(n)` | number, optional error message | Int, Float         | Multiple of validation    |

### Array Methods

| Method            | Parameters | Description          |
| ----------------- | ---------- | -------------------- |
| `@zod.min(n)`     | number     | Minimum array length |
| `@zod.max(n)`     | number     | Maximum array length |
| `@zod.length(n)`  | number     | Exact array length   |
| `@zod.nonempty()` | none       | Non-empty array      |

### Date Methods

| Method           | Parameters | Description  |
| ---------------- | ---------- | ------------ |
| `@zod.min(date)` | Date       | Minimum date |
| `@zod.max(date)` | Date       | Maximum date |

### Field Modifiers

| Method                | Parameters | Description                            |
| --------------------- | ---------- | -------------------------------------- |
| `@zod.optional()`     | none       | Make field optional                    |
| `@zod.nullable()`     | none       | Make field nullable                    |
| `@zod.nullish()`      | none       | Make field nullish (null or undefined) |
| `@zod.default(value)` | any value  | Set default value                      |

### Custom Validation

| Method               | Parameters | Description                |
| -------------------- | ---------- | -------------------------- |
| `@zod.refine(fn)`    | function   | Custom validation function |
| `@zod.transform(fn)` | function   | Value transformation       |
| `@zod.enum(options)` | array      | Enum validation            |

### Special Types

| Method                | Parameters      | Field Types | Description              |
| --------------------- | --------------- | ----------- | ------------------------ |
| `@zod.json()`         | none            | Json        | JSON validation          |
| `@zod.object()`       | none            | Any         | Object validation        |
| `@zod.array()`        | optional schema | Any         | Array validation         |
| `@zod.custom(schema)` | object literal  | Json        | Structured object schema |

## Parameter Types Supported

The generator preserves all JavaScript parameter types:

- **Strings**: `@zod.nanoid('Custom error')` → `z.nanoid('Custom error')`
- **Objects**: `@zod.nanoid({ abort: true })` → `z.nanoid({"abort":true})`
- **Numbers**: `@zod.min(10)` → `z.string().min(10)`
- **Booleans**: `@zod.optional()` → `z.string().optional()`
- **Arrays**: `@zod.custom([1, 2, 3])` → `z.custom([1,2,3])`
- **RegExp**: `@zod.regex(/pattern/)` → `z.regex(/pattern/)`
- **Function calls**: `@zod.custom(Date.now())` → `z.custom(Date.now())`
- **Nested expressions**: `@zod.custom(new RegExp('.'))` → `z.custom(new RegExp('.'))`

# Circular Dependency Exclusion

## Problem

When using `pureModelsIncludeRelations: true` with bidirectional relationships, you may encounter TypeScript circular dependency errors:

```
'DealSchema' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer
```

This happens with relationships like:

- `Deal` ↔ `Opportunity` (one-to-one bidirectional)
- `User` ↔ `Profile` (one-to-one with FK)
- `Category` → `Category` (self-referencing hierarchies)

## Solution

Use the `pureModelsExcludeCircularRelations` option to intelligently exclude problematic relation fields while preserving foreign keys and important relationships.

```json title="zod-generator.config.json"
{
  "mode": "custom",
  "pureModels": true,
  "pureModelsIncludeRelations": true,
  "pureModelsExcludeCircularRelations": true,
  "variants": {
    "pure": { "enabled": true }
  },
  "emit": {
    "objects": false,
    "crud": false
  }
}
```

## Schema Example

```prisma title="schema.prisma"
model Deal {
  id          String  @id @default(uuid())
  name        String?
  status      String  @default("DRAFT")

  // This back-reference will be excluded
  opportunity Opportunity?
}

model Opportunity {
  id     String @id @default(uuid())
  name   String

  // Foreign key preserved, relation preserved
  dealId String? @unique
  deal   Deal?   @relation(fields: [dealId], references: [id])
}
```

## What gets excluded

The feature uses smart heuristics to determine which relations to exclude:

1. **Preserves required relations** over optional ones
2. **Preserves single relations** over list relations
3. **Preserves FK-side relations** over back-references
4. **Handles self-references** by excluding one of multiple self-referencing fields

## Generated Output

**Before (with circular dependency):**

```typescript
// Deal.model.ts
import { OpportunitySchema } from './Opportunity.model'; // ❌ Circular import
export const DealSchema = z.object({
  opportunity: z.lazy(() => OpportunitySchema).nullish(),
});

// Opportunity.model.ts
import { DealSchema } from './Deal.model'; // ❌ Circular import
export const OpportunitySchema = z.object({
  dealId: z.string().nullish(),
  deal: z.lazy(() => DealSchema).nullish(), // ❌ Causes circular dependency
});
```

**After (circular dependency resolved):**

```typescript
// Deal.model.ts
import { OpportunitySchema } from './Opportunity.model'; // ✅ One-way import
export const DealSchema = z.object({
  opportunity: z.lazy(() => OpportunitySchema).nullish(), // ✅ Works!
});

// Opportunity.model.ts
export const OpportunitySchema = z.object({
  dealId: z.string().nullish(), // ✅ Foreign key preserved
  // deal field excluded to break circular reference
});
```

## Configuration Methods

### Via JSON Config

```json title="zod-generator.config.json"
{
  "pureModelsExcludeCircularRelations": true
}
```

### Via Generator Block

```prisma title="schema.prisma"
generator zod {
  provider = "prisma-zod-generator"
  pureModelsExcludeCircularRelations = "true"
}
```

## Use Cases

- **API validation** - Clean schemas without circular dependencies
- **Form validation** - Include relations but avoid TypeScript errors
- **Data transformation** - Preserve essential relationships while maintaining type safety
- **Legacy migration** - Smooth transition from other schema generators like `zod-prisma`

## Migration from zod-prisma

This feature helps migrate from `zod-prisma`, which would "just use dealId and not include the self reference to the DealSchema." The new option provides the same clean output while giving you control over when to include relations.

# CRUD Only

Skip pure model variant and focus on object + CRUD argument schemas:

```jsonc
{
  "pureModels": false,
  "emit": { "pureModels": false, "objects": true, "crud": true, "variants": false },
}
```

# Flexible API Validation

This recipe shows how to configure the generator to allow extra fields in API requests while maintaining strict validation for internal schemas.

## Problem

By default, all generated Zod schemas include `.strict()`, which rejects any extra properties. This can be problematic when:

- Integrating with external APIs that send additional fields
- Building APIs that should ignore unknown fields
- Developing frontend applications that might send extra data

## Solution

Use strict mode configuration to disable `.strict()` for operation schemas while keeping it for internal object schemas:

```json title="zod-generator.config.json"
{
  "strictMode": {
    "enabled": true,      // Keep strict by default
    "operations": false,  // Allow extra fields in API operations
    "objects": true,      // Keep strict for internal validation
    "variants": true      // Keep strict for type variants
  }
}
```

## Result

### Before (Default Strict)

```typescript
// API operation schema - rejects extra fields
export const CreateOneUserArgsSchema = z.object({
  data: UserCreateInputSchema
}).strict(); // ← Rejects extra fields

// Internal object schema - rejects extra fields
export const UserCreateInputSchema = z.object({
  name: z.string(),
  email: z.string()
}).strict(); // ← Rejects extra fields
```

### After (Flexible Operations)

```typescript
// API operation schema - allows extra fields
export const CreateOneUserArgsSchema = z.object({
  data: UserCreateInputSchema
}); // ← No .strict() - allows extra fields

// Internal object schema - still strict
export const UserCreateInputSchema = z.object({
  name: z.string(),
  email: z.string()
}).strict(); // ← Still strict for internal validation
```

## Usage Example

### Client Request (Now Works)

```typescript
// This request now succeeds even with extra fields
const response = await fetch('/api/users', {
  method: 'POST',
  body: JSON.stringify({
    data: {
      name: 'John Doe',
      email: 'john@example.com',
      // Extra fields from frontend - now ignored instead of rejected
      clientVersion: '1.2.3',
      trackingId: 'abc123',
      timestamp: Date.now()
    }
  })
});
```

### Server Validation

```typescript
import { CreateOneUserArgsSchema } from './generated/schemas';

export async function createUser(req: Request) {
  // Parse and validate - extra fields are ignored
  const parsed = CreateOneUserArgsSchema.parse(req.body);

  // Only the defined fields are present
  console.log(parsed);
  // { data: { name: 'John Doe', email: 'john@example.com' } }

  // Safe to pass to Prisma
  const user = await prisma.user.create(parsed);
  return user;
}
```

## Advanced Configuration

### Per-Model Flexibility

Allow extra fields only for specific models:

```json title="zod-generator.config.json"
{
  "strictMode": {
    "enabled": true,      // Strict by default
    "operations": true    // Operations strict by default
  },
  "models": {
    "User": {
      "strictMode": {
        "operations": false  // Only User operations allow extra fields
      }
    },
    "PublicProfile": {
      "strictMode": {
        "enabled": false     // All PublicProfile schemas allow extra fields
      }
    }
  }
}
```

### Operation-Specific Control

Allow extra fields only for specific operations:

```json title="zod-generator.config.json"
{
  "models": {
    "User": {
      "strictMode": {
        "operations": ["create", "update"],  // Only create/update allow extras
        "exclude": ["findMany"]              // findMany remains strict
      }
    }
  }
}
```

## Environment-Based Configuration

### Development (Permissive)

```json title="zod-generator.config.dev.json"
{
  "strictMode": {
    "enabled": false,     // Allow extra fields everywhere
    "variants": true,     // Keep variants strict for type safety
    "enums": true        // Keep enums strict
  }
}
```

### Production (Strict)

```json title="zod-generator.config.prod.json"
{
  "strictMode": {
    "enabled": true,      // Strict everywhere
    "operations": false   // Except operations (for API flexibility)
  }
}
```

Use different configs based on environment:

```prisma title="schema.prisma"
generator zod {
  provider = "prisma-zod-generator"
  output   = "./generated/schemas"
  config   = env("NODE_ENV") == "production" ? "./zod-generator.config.prod.json" : "./zod-generator.config.dev.json"
}
```

## Best Practices

1. **Start Conservative**: Begin with strict validation and selectively allow flexibility
2. **Validate Boundaries**: Keep internal schemas strict while allowing flexibility at API boundaries
3. **Test Thoroughly**: Ensure your application handles extra fields gracefully
4. **Document Decisions**: Comment why certain models/operations allow extra fields
5. **Monitor Production**: Log when extra fields are received to understand usage patterns

## Related Patterns

- **Gradual Migration**: Gradually moving from strict to flexible validation
- **Input Validation**: Different validation strategies for different schema types
- **API Integration**: Working with external APIs that send extra data

## Common Issues

### Still Getting Validation Errors

If you're still getting strict validation errors:

1. Check that you're using operation schemas (e.g., `CreateOneUserArgsSchema`) not object schemas
2. Verify your configuration is properly loaded
3. Ensure you've regenerated schemas after configuration changes

### Performance Considerations

Allowing extra fields has minimal performance impact, but consider:

- Extra fields are parsed but ignored (not passed to Prisma)
- Large payloads with many extra fields use more memory during parsing
- Consider request size limits for APIs that accept extra fields

# Granular Per Model

```jsonc
{
  "mode": "custom",
  "models": {
    "User": {
      "operations": ["findMany", "create"],
      "variants": { "input": { "excludeFields": ["role"] } },
    },
    "Post": {
      "operations": ["findMany", "findUnique"],
      "variants": { "result": { "excludeFields": ["internalFlag"] } },
    },
  },
}
```

Enables partial surface per model.

# Hide Sensitive Fields

```jsonc
{
  "globalExclusions": { "result": ["password", "hashedPassword", "secret*"] },
}
```

Removes sensitive fields from outward-facing result schemas.

# Input Variant Only

```jsonc
{
  "variants": {
    "pure": { "enabled": false },
    "input": { "enabled": true },
    "result": { "enabled": false },
  },
  "emit": { "pureModels": false },
}
```

For update operations, enable the partial flag to make all fields optional:

```jsonc
{
  "variants": {
    "pure": { "enabled": false },
    "input": {
      "enabled": true,
      "partial": true  // Makes all fields optional with .partial()
    },
    "result": { "enabled": false },
  },
  "emit": { "pureModels": false },
}
```

Good for request validation only.

# JSON-friendly DateTime (Split Strategy Default)

This recipe shows how the default split strategy for DateTime improves JSON API ergonomics:

- Input schemas accept ISO datetime strings via `z.coerce.date()`
- Pure model and result schemas remain strict `z.date()`

The split behavior is enabled by default via `dateTimeSplitStrategy: true`. You can still override globally with `dateTimeStrategy`.

Why this matters

- Most clients send ISO strings in JSON. With the split default, creates/updates parse ISO strings without extra code, while output and model snapshots keep strong Date objects.

Minimal configuration

```jsonc
// zod-generator.config.json
{
  "mode": "custom",
  "output": "./generated",
  // enabled by default; shown here for clarity
  "dateTimeSplitStrategy": true,
  "variants": {
    "pure":   { "enabled": true, "suffix": ".model" },
    "input":  { "enabled": true, "suffix": ".input" },
    "result": { "enabled": true, "suffix": ".result" }
  }
}
```

Example model

```prisma
model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  posts     Post[]
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  author   User?     @relation(fields: [authorId], references: [id])
  authorId Int?
}
```

Sample JSON payload accepted by Create/Update inputs

```json
{
  "data": {
    "title": "Hello World",
    "createdAt": "2025-01-01T00:00:00.000Z",
    "author": { "connect": { "email": "alice@example.com" } }
  }
}
```

Overrides (optional)

- Force `coerce` across all variants:

```jsonc
{ "dateTimeStrategy": "coerce" }
```

- Force strict `date` across all variants:

```jsonc
{ "dateTimeStrategy": "date" }
```

- Force `isoString` across all variants:

```jsonc
{ "dateTimeStrategy": "isoString" }
```

Related changes

- WhereUniqueInput relies on base object validation. Composite unique selectors are enforced by their nested schemas. If you want early failure when no selector is provided, enable `validateWhereUniqueAtLeastOne: true` in your config.

References

- Configuration → DateTime Strategy: config/datetime-strategy
- Reference → WhereUniqueInput Semantics: reference/where-unique-input

# Minimal CRUD

```jsonc
{
  "mode": "minimal",
  "pureModels": true,
  "variants": {
    "pure": { "enabled": true },
    "input": { "enabled": true },
    "result": { "enabled": false },
  },
}
```

Produces lean create/update/find schemas, prunes deep nested inputs, disables select/include.

## Schema Generation Behavior

In minimal mode, the generator optimizes schema generation for simplicity and performance:

### Create Operations

- **Uses `UncheckedCreateInput` schemas only**: Create operations (e.g., `UserCreateOne`) use only `UncheckedCreateInputObjectSchema` instead of the union of both `CreateInput` and `UncheckedCreateInput`
- **Blocks complex `CreateInput` schemas**: Regular `*CreateInput.schema.ts` files are not generated since they require complex nested relation objects
- **Favors foreign keys**: `UncheckedCreateInput` schemas use simple foreign key fields (e.g., `userId: string`) instead of nested relation objects (e.g., `user: UserCreateNestedOneInput`)

### Update Operations

- **Allows both variants**: Update operations continue to support both `UpdateInput` and `UncheckedUpdateInput` schemas
- **Maintains flexibility**: Users can choose between relation-based updates or foreign key-based updates

### Blocked Schema Types

Minimal mode blocks generation of these complex input types:

- `*CreateInput` (regular, relation-based)
- `*CreateNestedInput`
- `*CreateWithoutInput`
- `*CreateOrConnectWithoutInput`
- `*CreateManyWithoutInput`
- Various nested and relation-heavy input schemas

### Example Output

```typescript
// ✅ Generated in minimal mode
export const UserCreateOneSchema = z.object({
  data: UserUncheckedCreateInputObjectSchema  // Only unchecked variant
})

// ✅ Generated - UncheckedCreateInput with foreign keys
export const UserUncheckedCreateInputObjectSchema = z.object({
  id: z.string().optional(),
  companyId: z.string(),  // Foreign key instead of nested relation
  name: z.string(),
  email: z.string()
})

// ❌ Not generated in minimal mode - would require complex relations
// UserCreateInputObjectSchema with nested { company: CompanyCreateNestedOneInput }
```

This approach ensures TypeScript compatibility while keeping the generated schemas lean and focused on essential CRUD operations.

# Models Only

Emit only pure model schemas (no CRUD/object scaffolding):

```jsonc
{
  "mode": "custom",
  "pureModels": true,
  "variants": {
    "pure": { "enabled": true },
    "input": { "enabled": false },
    "result": { "enabled": false },
  },
  "emit": { "objects": false, "crud": false, "variants": false },
}
```

Triggers "pureModelsOnly" heuristic; keeps output minimal.

# Optional Field Control

Configure how optional Prisma fields are validated using different Zod patterns.

## Use Cases

### API with Null Values

When your API accepts explicit null values alongside undefined/omitted fields:

```prisma
generator zod {
  provider = "prisma-zod-generator"
  optionalFieldBehavior = "nullish"  # default
}

model User {
  id   Int     @id
  name String?
  bio  String?
}
```

Generated schema accepts all these patterns:

```typescript
// All valid
{ id: 1, name: "John", bio: "Developer" }
{ id: 1, name: null, bio: undefined }
{ id: 1 } // name and bio omitted
```

### Strict No-Null API

When you want to reject explicit null values:

```prisma
generator zod {
  provider = "prisma-zod-generator"
  optionalFieldBehavior = "optional"
}
```

Generated validation:

```typescript
// Valid
{ id: 1, name: "John" }
{ id: 1 } // name omitted

// Invalid - null rejected
{ id: 1, name: null } // ❌ Validation error
```

### Always-Present Fields

When optional fields must always be included in requests:

```prisma
generator zod {
  provider = "prisma-zod-generator"
  optionalFieldBehavior = "nullable"
}
```

Generated validation:

```typescript
// Valid
{ id: 1, name: "John", bio: "Developer" }
{ id: 1, name: null, bio: null }

// Invalid - fields must be present
{ id: 1 } // ❌ Missing name and bio
```

## Configuration Options

### Generator Block

```prisma
generator zod {
  provider = "prisma-zod-generator"
  optionalFieldBehavior = "nullish" | "optional" | "nullable"
}
```

### JSON Config

```json
{
  "optionalFieldBehavior": "nullish"
}
```

## Comparison Table

| Behavior   | Zod Output    | Accepts `undefined` | Accepts `null` | Allows Omitted |
| ---------- | ------------- | ------------------- | -------------- | -------------- |
| `nullish`  | `.nullish()`  | ✅                   | ✅              | ✅              |
| `optional` | `.optional()` | ✅                   | ❌              | ✅              |
| `nullable` | `.nullable()` | ❌                   | ✅              | ❌              |

## Migration Example

Changing from the legacy `.optional().nullable()` pattern:

**Before:**

```typescript
// Legacy behavior (equivalent to nullish)
name: z.string().optional().nullable();
```

**After with explicit configuration:**

```typescript
// With optionalFieldBehavior = "nullish"
name: z.string().nullish();

// With optionalFieldBehavior = "optional"
name: z.string().optional();

// With optionalFieldBehavior = "nullable"
name: z.string().nullable();
```

## Type Safety

All behaviors maintain compatibility with Prisma types:

```typescript
import { Prisma } from '@prisma/client';

// Prisma type: { name?: string | null }
const data: Prisma.UserCreateInput = {
  id: 1,
  name: null, // Prisma allows null
};

// All optionalFieldBehavior settings accept this
UserCreateInputSchema.parse(data); // ✅ Always works
```

## Related: Variant Partial Flag

The `optionalFieldBehavior` setting controls how **Prisma optional fields** (like `String?`) are handled. For making **all fields optional** in specific variants, use the [partial flag in variants configuration](../config/variants.md#partial-flag):

```json
{
  "optionalFieldBehavior": "optional",  // Controls Prisma optional fields
  "variants": {
    "input": {
      "enabled": true,
      "partial": true  // Makes ALL fields optional with .partial()
    }
  }
}
```

Key differences:

- **`optionalFieldBehavior`**: Controls only Prisma optional fields (`String?`)
- **`partial` flag**: Makes ALL fields optional in specific variants

# Pure Models Lean

Remove heavy relation fields globally:

```jsonc
{
  "pureModels": true,
  "pureModelsLean": true,
  "pureModelsIncludeRelations": false,
  "globalExclusions": { "pure": ["*Relation", "posts", "comments"] },
}
```

Generates scalar-centric schemas for simpler validation surfaces.

# Result Variant Only

Focus on response shaping for outbound APIs:

```jsonc
{
  "mode": "custom",
  "variants": {
    "pure": { "enabled": false },
    "input": { "enabled": false },
    "result": { "enabled": true },
  },
  "emit": { "pureModels": false },
}
```

# Custom Safety Configuration

# Custom Safety Configuration

This recipe demonstrates how to create custom safety configurations tailored to your specific project needs.

## Overview

The safety system offers granular control over different types of protections. You can mix and match settings to create a configuration that works for your project structure.

## Complete Configuration Example

```json title="zod-generator.config.json"
{
  "safety": {
    "level": "standard",
    "allowDangerousPaths": false,
    "allowProjectRoots": false,
    "allowUserFiles": false,
    "skipManifest": false,
    "warningsOnly": false,
    "maxUserFiles": 10,
    "customDangerousPaths": ["modules", "widgets"],
    "customProjectFiles": ["project.config.js", "build.config.js"]
  }
}
```

## Configuration Options

### Safety Levels (Presets)

Choose a base level, then override specific settings:

```json
{
  "safety": {
    "level": "strict",        // strict | standard | permissive | disabled
    "allowUserFiles": true    // Override the preset
  }
}
```

**Available levels**:

- `strict` - Maximum protection, blocks even small numbers of user files
- `standard` - Balanced protection (default)
- `permissive` - Warnings-heavy, minimal blocking
- `disabled` - No safety checks

### Individual Controls

#### allowDangerousPaths

Controls whether common source directory names are allowed:

```json
{
  "safety": {
    "allowDangerousPaths": true  // Allow src, lib, components, etc.
  }
}
```

**Default dangerous paths**: `src`, `lib`, `components`, `pages`, `app`, `utils`, `hooks`, `services`, `api`

#### allowProjectRoots

Controls whether directories containing project files are allowed:

```json
{
  "safety": {
    "allowProjectRoots": true  // Allow dirs with package.json, tsconfig.json, etc.
  }
}
```

#### allowUserFiles

Controls whether directories with user files are allowed:

```json
{
  "safety": {
    "allowUserFiles": true,
    "maxUserFiles": 20  // Only relevant when allowUserFiles is false
  }
}
```

#### skipManifest

Disables manifest tracking and smart cleanup:

```json
{
  "safety": {
    "skipManifest": true  // No manifest file, no selective cleanup
  }
}
```

#### warningsOnly

Converts all safety errors to warnings:

```json
{
  "safety": {
    "warningsOnly": true  // Never block generation, only warn
  }
}
```

### Custom Patterns

#### customDangerousPaths

Add your own dangerous directory patterns:

```json
{
  "safety": {
    "customDangerousPaths": ["modules", "widgets", "core"]
  }
}
```

#### customProjectFiles

Add your own project file patterns:

```json
{
  "safety": {
    "customProjectFiles": [
      "nuxt.config.js",
      "svelte.config.js", 
      "astro.config.mjs"
    ]
  }
}
```

## Common Scenarios

### Scenario 1: Strict Enterprise Environment

Maximum safety for large teams:

```json title="zod-generator.config.json"
{
  "safety": {
    "level": "strict",
    "maxUserFiles": 0,
    "customProjectFiles": [
      ".eslintrc.js",
      "jest.config.js",
      "docker-compose.yml"
    ]
  }
}
```

### Scenario 2: Flexible Development Environment

Balanced approach for active development:

```json title="zod-generator.config.json"
{
  "safety": {
    "level": "standard",
    "allowDangerousPaths": true,
    "maxUserFiles": 15,
    "warningsOnly": false
  }
}
```

### Scenario 3: Legacy Project Migration

Permissive settings for migrating existing projects:

```json title="zod-generator.config.json"
{
  "safety": {
    "level": "permissive", 
    "allowUserFiles": true,
    "customDangerousPaths": ["legacy", "old-modules"]
  }
}
```

### Scenario 4: CI/CD Environment

Automated environments with controlled paths:

```json title="zod-generator.config.json"
{
  "safety": {
    "level": "standard",
    "skipManifest": true,      // No state between runs
    "allowDangerousPaths": false,
    "warningsOnly": true       // Don't fail builds on warnings
  }
}
```

## Multiple Configuration Sources

Configurations are merged with this precedence:

1. **Environment variables** (highest priority)
2. **Generator block options**
3. **Config file settings**
4. **Default values** (lowest priority)

### Environment Variables

```bash title=".env"
PRISMA_ZOD_SAFETY_LEVEL=permissive
PRISMA_ZOD_SAFETY_ALLOW_DANGEROUS_PATHS=true
PRISMA_ZOD_SAFETY_MAX_USER_FILES=25
PRISMA_ZOD_SAFETY_CUSTOM_DANGEROUS_PATHS=modules,widgets
```

### Generator Block

```prisma title="schema.prisma"
generator zod {
  provider                      = "prisma-zod-generator"
  output                        = "./src/generated"
  safetyLevel                  = "standard"
  safetyAllowDangerousPaths    = false
  safetyMaxUserFiles           = "10"
  safetyCustomDangerousPaths   = "modules,widgets"
}
```

### Config File

```json title="zod-generator.config.json"
{
  "output": "./generated",
  "safety": {
    "level": "strict",
    "customDangerousPaths": ["legacy"]
  }
}
```

## Testing Your Configuration

Create a test directory structure to verify your safety configuration:

```bash
mkdir -p test-safety/{src,components,package.json}
echo '{"name":"test"}' > test-safety/package.json
echo 'const x = 1;' > test-safety/src/test.ts
```

Then test with different configurations:

```prisma title="test-schema.prisma"
generator zod {
  provider    = "prisma-zod-generator" 
  output      = "./test-safety/src"
  safetyLevel = "standard"  // Try different levels
}

model User {
  id String @id
}
```

## Configuration Validation

The system validates your configuration and provides helpful error messages:

```json title="Invalid configuration"
{
  "safety": {
    "level": "invalid-level",     // ❌ Error: Invalid safety level
    "maxUserFiles": -5            // ❌ Error: Must be non-negative
  }
}
```

## Debugging Safety Issues

Enable debug logging to understand safety decisions:

```bash
DEBUG=prisma-zod-generator* npx prisma generate
```

Or check the generated manifest file:

```json title=".prisma-zod-generator-manifest.json"
{
  "version": "1.0",
  "generatedAt": "2024-01-15T10:30:00.000Z",
  "files": ["User.schema.ts", "Post.schema.ts"],
  "directories": ["enums"]
}
```

## Best Practices

1. **Start Strict**: Begin with `"level": "strict"` and relax as needed
2. **Test Configurations**: Use a copy of your project to test safety settings
3. **Document Choices**: Comment your configuration choices for team members
4. **Review Regularly**: Periodically review if you can tighten safety settings
5. **Use Version Control**: Always commit before changing safety configurations

## Migration Path

When changing safety configurations:

1. **Commit Current State**: Save your work
2. **Test New Configuration**: Try on a project copy first
3. **Update Gradually**: Make incremental changes
4. **Monitor Warnings**: Watch for new warning patterns
5. **Update Team**: Inform team members of configuration changes

***

:::tip Pro Tip
Use environment variables for temporary safety overrides during debugging, but keep your permanent configuration in the config file or generator block for consistency.
:::

# Disable Safety System Completely

# Disable Safety System Completely

This recipe shows how to completely disable the safety system that protects against dangerous output paths.

:::danger
Only disable safety checks if you fully understand the risks. The safety system prevents accidental deletion of your source code. Use this configuration with extreme caution.
:::

## When to Use

- You're an experienced user who fully understands the implications
- You have robust backup and version control practices
- You're using the generator in automated environments with careful path management
- You need to temporarily bypass safety for migration purposes

## Configuration

### Method 1: Config File

```json title="zod-generator.config.json"
{
  "safety": {
    "enabled": false
  }
}
```

### Method 2: Prisma Generator Block

```prisma title="schema.prisma"
generator zod {
  provider      = "prisma-zod-generator"
  output        = "./src"  // Now allowed (dangerous!)
  safetyEnabled = false
}
```

### Method 3: Environment Variable

```bash title=".env"
PRISMA_ZOD_SAFETY_ENABLED=false
```

```bash title="Command line"
PRISMA_ZOD_SAFETY_ENABLED=false npx prisma generate
```

## What This Does

With safety disabled:

- ✅ All output paths are allowed, including dangerous ones
- ✅ No warnings or errors about path safety
- ✅ No manifest tracking or cleanup protection
- ❌ **Your files can be deleted without warning**

## Example Output

```bash
# Before (with safety enabled)
❌ ERROR: Unsafe output path detected: Output directory contains project file "package.json"

# After (with safety disabled)  
✅ Generation completed successfully
```

## Alternative: Use Permissive Mode

Instead of completely disabling safety, consider using permissive mode which still provides some protection:

```json title="zod-generator.config.json"
{
  "safety": {
    "level": "permissive"  // Warns but doesn't block
  }
}
```

## Safety Recommendations

If you disable safety:

1. **Always use version control** - Commit your changes before running the generator
2. **Use specific paths** - Point to dedicated directories, not source roots
3. **Test carefully** - Run on a copy of your project first
4. **Re-enable when possible** - Turn safety back on once you've restructured

## Re-enabling Safety

To re-enable safety later:

```json title="zod-generator.config.json"
{
  "safety": {
    "enabled": true,
    "level": "standard"  // or "strict" for maximum protection
  }
}
```

Or remove the configuration entirely to use defaults.

***

:::tip
Consider using [force dangerous paths](./safety-force-dangerous-path.md) or [custom safety configuration](./safety-custom-configuration.md) instead of completely disabling safety.
:::

# Force Using Dangerous Paths

# Force Using Dangerous Paths

This recipe shows how to configure the generator to allow potentially dangerous output paths while keeping basic safety protections.

:::warning
This configuration allows dangerous paths but still protects against the worst scenarios like project root directories. Use with caution.
:::

## When to Use

- You need to output directly to source directories (e.g., `./src`, `./lib`)
- You have existing projects with schemas in source folders
- You want warnings but not blocking behavior
- You understand the risks but need flexibility

## Configuration Options

### Method 1: Allow Dangerous Paths Only

```json title="zod-generator.config.json"
{
  "safety": {
    "allowDangerousPaths": true
  }
}
```

```prisma title="schema.prisma"
generator zod {
  provider                    = "prisma-zod-generator"
  output                      = "./src"
  safetyAllowDangerousPaths  = true
}
```

### Method 2: Permissive Mode (Recommended)

```json title="zod-generator.config.json"
{
  "safety": {
    "level": "permissive"
  }
}
```

```prisma title="schema.prisma"
generator zod {
  provider    = "prisma-zod-generator"
  output      = "./src"
  safetyLevel = "permissive"
}
```

### Method 3: Warnings Only

```json title="zod-generator.config.json"
{
  "safety": {
    "warningsOnly": true
  }
}
```

## What Each Approach Does

### Allow Dangerous Paths Only

- ✅ Allows `src`, `lib`, `components` etc. directories
- ⚠️  Still warns about user files if no manifest exists
- ❌ Still blocks project root directories (with `package.json`)
- ✅ Maintains manifest tracking and smart cleanup

### Permissive Mode

- ✅ Allows dangerous paths with warnings
- ✅ Allows user files (with warnings)
- ❌ Still blocks project roots (safer)
- ✅ Only shows warnings, never blocks generation
- ✅ Full manifest tracking

### Warnings Only

- ⚠️  Shows warnings for all safety issues
- ✅ Never blocks generation
- ✅ Maintains all safety protections except blocking
- ✅ Full manifest tracking

## Example Scenarios

### Scenario 1: Existing Project with Schemas in src/

```prisma title="schema.prisma"
generator zod {
  provider                   = "prisma-zod-generator"
  output                     = "./src/schemas"
  safetyAllowDangerousPaths = true
}
```

**Result**:

- ✅ Generates to `src/schemas/`
- ⚠️  Warning about "src" being dangerous
- ✅ Manifest tracking prevents deleting your other `src/` files

### Scenario 2: Component-Colocated Schemas

```json title="zod-generator.config.json"
{
  "safety": {
    "level": "permissive",
    "customDangerousPaths": ["components"]
  }
}
```

```prisma title="schema.prisma"
generator zod {
  provider = "prisma-zod-generator"
  output   = "./components/schemas"
}
```

**Result**:

- ✅ Generates to `components/schemas/`
- ⚠️  Warnings but no blocking
- ✅ Your existing components remain safe

## Still Protected Against

Even with dangerous paths allowed, you're still protected from:

- **Project root directories** - Directories with `package.json`, `tsconfig.json` etc.
- **Too many user files** - If manifest is missing and many user files exist
- **Complete chaos** - Basic sanity checks remain active

## Environment Variable Override

You can temporarily allow dangerous paths via environment variables:

```bash
PRISMA_ZOD_SAFETY_ALLOW_DANGEROUS_PATHS=true npx prisma generate
```

## Safety Progression

Here's a recommended progression from safest to most permissive:

### 1. Default (Safest)

```json
{
  "safety": {
    "level": "standard"  // Default
  }
}
```

### 2. Allow Your Specific Dangerous Path

```json
{
  "safety": {
    "allowDangerousPaths": true
  }
}
```

### 3. Permissive Mode

```json
{
  "safety": {
    "level": "permissive"
  }
}
```

### 4. Warnings Only

```json
{
  "safety": {
    "warningsOnly": true
  }
}
```

### 5. Disabled (Most Dangerous)

```json
{
  "safety": {
    "enabled": false
  }
}
```

## Best Practices

1. **Start Conservative**: Begin with `allowDangerousPaths: true` rather than disabling safety entirely

2. **Use Specific Paths**: Instead of outputting to `./src`, use `./src/generated` or `./src/schemas`

3. **Monitor Warnings**: Pay attention to warning messages - they guide you toward safer configurations

4. **Backup First**: Always commit your changes before running generation with relaxed safety

5. **Review Manifest**: Check the `.prisma-zod-generator-manifest.json` file to understand what will be cleaned up

## Migration Strategy

If you're migrating from a setup that pointed to dangerous paths:

```prisma title="Before (dangerous)"
generator zod {
  provider = "prisma-zod-generator"
  output   = "./src"
}
```

```prisma title="After (safer, but compatible)"
generator zod {
  provider                   = "prisma-zod-generator"
  output                     = "./src/generated"  // Dedicated subdirectory
  safetyAllowDangerousPaths = false              // Can remove this line
}
```

Then update your imports:

```typescript
// Before
import { UserSchema } from './User.schema';

// After  
import { UserSchema } from './generated/User.schema';
```

***

:::info
This approach provides a good balance between safety and flexibility. You get protection against the worst scenarios while still being able to use source directories when necessary.
:::

# Project Migration Safety Guide

# Project Migration Safety Guide

This guide helps you migrate existing projects that may have unsafe generator configurations to use the new safety system.

## Common Migration Scenarios

### Scenario 1: Generator Points to Source Directory

**Before (Unsafe)**:

```prisma title="schema.prisma"
generator zod {
  provider = "prisma-zod-generator"
  output   = "./src"  // Dangerous - points to entire src directory
}
```

**Migration Options**:

#### Option A: Move to Dedicated Directory (Recommended)

```prisma title="schema.prisma"  
generator zod {
  provider = "prisma-zod-generator"
  output   = "./generated"  // Safe dedicated directory
}
```

**Steps**:

1. Update schema.prisma
2. Run generator to create new location
3. Update all imports in your code
4. Delete old generated files from src/
5. Test thoroughly

#### Option B: Use Subdirectory in Source

```prisma title="schema.prisma"
generator zod {
  provider = "prisma-zod-generator" 
  output   = "./src/generated"  // Safer subdirectory
}
```

#### Option C: Allow Dangerous Path Temporarily

```prisma title="schema.prisma"
generator zod {
  provider                   = "prisma-zod-generator"
  output                     = "./src"
  safetyAllowDangerousPaths = true  # Temporary workaround
}
```

:::warning
Option C is a temporary solution. Plan to migrate to Option A or B.
:::

### Scenario 2: Generator in Project Root

**Before (Very Unsafe)**:

```prisma title="schema.prisma"
generator zod {
  provider = "prisma-zod-generator"
  output   = "."  // Extremely dangerous - project root!
}
```

This configuration is now **blocked by default**. You must migrate:

**Migration (Required)**:

```prisma title="schema.prisma"
generator zod {
  provider = "prisma-zod-generator"
  output   = "./prisma/generated"  // Safe location
}
```

### Scenario 3: Mixed Generated and Source Files

**Before**: Generated files mixed with your code in `src/`

**Migration Strategy**:

1. **Identify Generated Files**: Look for files that match typical generated patterns
2. **Create Manifest**: Use the manifest system to track future generations
3. **Separate Gradually**: Move generated files to dedicated directories

```bash title="Identify generated files"
# Look for common patterns
find src/ -name "*.schema.ts"
find src/ -name "*CreateInput.ts" 
find src/ -name "*WhereInput.ts"
```

```prisma title="New configuration"
generator zod {
  provider = "prisma-zod-generator"
  output   = "./src/generated"
  
  # Allow the dangerous src path temporarily during migration
  safetyLevel = "permissive"
}
```

## Migration Strategies

### Strategy 1: Big Bang Migration

Move everything at once:

1. **Backup Project**: Commit all changes
2. **Update Configuration**: Change output path
3. **Run Generator**: Generate in new location
4. **Update Imports**: Use find-and-replace for import paths
5. **Clean Up**: Delete old files
6. **Test**: Verify everything works

```bash title="Find and replace imports"
# Example: Update imports from src/ to generated/
find . -name "*.ts" -exec sed -i 's|from "\.\/.*\.schema"|from "../generated/&"|g' {} \;
```

### Strategy 2: Gradual Migration

Migrate module by module:

1. **Dual Configuration**: Run generator in both old and new locations temporarily
2. **Migrate Modules**: Update imports module by module
3. **Clean Up Gradually**: Remove old files as you migrate imports
4. **Final Switch**: Once all imports updated, switch to new location only

### Strategy 3: Safety-First Migration

Use safety system to guide migration:

1. **Enable Warnings**: Use `warningsOnly: true` to see issues without blocking
2. **Analyze Warnings**: Understand what files would be affected
3. **Create Migration Plan**: Based on warning analysis
4. **Execute Plan**: Make changes guided by safety feedback

## Safety Configuration for Migration

### Phase 1: Assessment

```json title="zod-generator.config.json"
{
  "safety": {
    "level": "strict",
    "warningsOnly": true  // See all issues without blocking
  }
}
```

### Phase 2: Active Migration

```json title="zod-generator.config.json"  
{
  "safety": {
    "level": "permissive",
    "allowDangerousPaths": true,
    "allowUserFiles": true
  }
}
```

### Phase 3: Post-Migration

```json title="zod-generator.config.json"
{
  "safety": {
    "level": "standard"  // Return to normal safety
  }
}
```

## Handling Specific Error Messages

### Error: "Output directory contains project file"

```
❌ Output directory contains project file "package.json"
```

**Solutions**:

1. **Change Output**: Use a subdirectory instead
2. **Override Temporarily**: Set `allowProjectRoots: true`
3. **Environment Override**: `PRISMA_ZOD_SAFETY_ALLOW_PROJECT_ROOTS=true`

### Error: "Too many potentially user-generated files"

```
❌ Too many potentially user-generated files (15) found. Maximum allowed: 5.
```

**Solutions**:

1. **Increase Limit**: Set `maxUserFiles: 20`
2. **Allow User Files**: Set `allowUserFiles: true`
3. **Clean Directory**: Remove non-generated files first
4. **Use Manifest**: Let the system learn what's generated

### Warning: "Common source code directory name"

```
⚠️ Output directory "src" is a common source code directory name
```

**Solutions**:

1. **Use Subdirectory**: Change to `./src/generated`
2. **Allow Dangerous**: Set `allowDangerousPaths: true`
3. **Accept Warning**: Warnings don't block generation

## Import Update Strategies

### Automated Import Updates

```javascript title="update-imports.js"
const fs = require('fs');
const path = require('path');

function updateImports(directory, oldPath, newPath) {
  const files = fs.readdirSync(directory);
  
  files.forEach(file => {
    if (file.endsWith('.ts') || file.endsWith('.tsx')) {
      const filePath = path.join(directory, file);
      let content = fs.readFileSync(filePath, 'utf8');
      
      // Update relative imports
      content = content.replace(
        new RegExp(`from ['"]${oldPath}`, 'g'),
        `from "${newPath}`
      );
      
      fs.writeFileSync(filePath, content);
    }
  });
}

// Usage
updateImports('./src', './schemas/', '../generated/schemas/');
```

### VSCode Find and Replace

1. Open Find and Replace (Ctrl/Cmd + Shift + H)
2. Enable regex mode
3. Find: `from ['"]\.\/schemas\/`
4. Replace: `from "../generated/schemas/`

### TypeScript-Aware Refactoring

If using VSCode or WebStorm:

1. Rename the generated directory
2. Let the IDE update imports automatically
3. Run TypeScript compiler to catch any missed imports

## Validation After Migration

### Check 1: No TypeScript Errors

```bash
npx tsc --noEmit
```

### Check 2: All Imports Resolved

```bash
npm run build
```

### Check 3: Tests Pass

```bash
npm test
```

### Check 4: No Old Generated Files

```bash
# Look for old generated files in dangerous locations
find src/ -name "*.schema.ts" -not -path "*/generated/*"
```

## Rollback Plan

Always have a rollback plan:

1. **Git Branch**: Create a migration branch
2. **Backup Configuration**: Save old generator config
3. **Document Changes**: Keep notes of what imports were changed
4. **Test Rollback**: Verify you can revert changes

```bash title="Rollback commands"
git checkout main
git reset --hard HEAD~1  # If committed
# OR restore specific files
git checkout HEAD~1 -- schema.prisma src/
```

## Team Coordination

For team projects:

1. **Announce Migration**: Warn team about upcoming changes
2. **Create PR**: Use pull requests for review
3. **Document Process**: Share migration steps with team
4. **Coordinate Timing**: Choose low-activity periods
5. **Support Team**: Be available for migration questions

***

:::info
Migration can be complex, but the safety system is designed to help guide you through the process. Start with permissive settings and gradually tighten them as you clean up your project structure.
:::

# Single File Bundle

```jsonc
{
  "useMultipleFiles": false,
  "singleFileName": "schemas.ts",
  "pureModels": true,
  "variants": {
    "pure": { "enabled": true },
    "input": { "enabled": true },
    "result": { "enabled": false },
  },
}
```

Produces one portable file; variants directory suppressed.

# tRPC Optimized

```jsonc
{
  "mode": "custom",
  "output": "./generated/zod",
  "globalExclusions": {
    "input": ["id", "createdAt", "updatedAt"],
    "result": [],
    "pure": ["password", "hashedPassword"],
  },
  "variants": {
    "pure": { "enabled": true, "suffix": ".model" },
    "input": { "enabled": true, "suffix": ".input" },
    "result": { "enabled": true, "suffix": ".output" },
  },
}
```

Aligns with typical request/response patterns + internal model snapshot.

# Zod import targets

Control how generated schemas import Zod via the `zodImportTarget` config option.

Install Zod in your app (peer dependency), then pick one of:

- auto (default): `import * as z from 'zod'` (namespace import for better tree-shaking)
- v3: `import { z } from 'zod'` (named import for compatibility)
- v4: `import * as z from 'zod/v4'`

Notes

- In single‑file bundles, a single Zod import is hoisted at the top.
- This setting affects all generated files and variants.

Quick recipes

- Copy one of these into your config JSON:

```json title="zod-generator.config.json"
{ "zodImportTarget": "auto" }
```

```json title="zod-generator.config.json"
{ "zodImportTarget": "v4" }
```

See also

- Reference → Bytes and JSON
- Configuration → Modes and Variants

# Bytes & JSON Details

**Bytes** mapping logic:

- Default pure model output: base64 string + regex validation.
- Set `complexTypes.bytes.useBase64=false` to emit `Uint8Array` schemas.
- Size limits: `minSize` / `maxSize` adjust validation (base64 length scaled 4/3).
- Allowed MIME types recorded as comments (binary mode needs external detection).

**JSON** mapping options (when enhanced config present):

- Serializability refine (JSON.stringify guard)
- Max depth & length checks
- Null allowance toggles (record vs strict modes)

### Helper: jsonMaxDepthRefinement

Utility to append a depth guard to complex JSON array/object schemas.

```ts
import { jsonMaxDepthRefinement } from 'prisma-zod-generator';
const DeepJson = z.array(z.any())${'${jsonMaxDepthRefinement(8)}'};
```

Pass desired max depth; nodes beyond trigger validation error. Prefer modest limits (5–12) to avoid costly traversals.

# FAQ

## Pro Features

**How do I purchase pro features?**

Visit [github.com/sponsors/omar-dulaimi](https://github.com/sponsors/omar-dulaimi) and select your tier. After sponsoring, DM [@omardulaimidev on X](https://x.com/omardulaimidev) with your GitHub username to receive your license key and setup instructions.

**How do I get my license after purchasing?**

After purchasing through GitHub Sponsors, send a DM on X to [@omardulaimidev](https://x.com/omardulaimidev) with your GitHub username. You'll receive your license key and setup instructions within 24 hours.

**What's included in each tier?**

- **Starter ($69/year)**: Server Actions Pack, Form UX Pack
- **Professional ($199/year)**: All Starter features + SDK Publisher, API Docs Pack, Policies & Redaction, Drift Guard, PostgreSQL RLS, Performance Pack
- **Business ($599/year)**: All Professional features + Contract Testing, Data Factories
- **Enterprise (Custom pricing)**: Everything + Multi-Tenant Kit, roadmap reviews, custom feature collaboration

See [full pricing details](/pricing) for complete tier comparison.

**Can I upgrade or downgrade my tier?**

Yes, you can adjust your GitHub Sponsors tier at any time. Contact [@omardulaimidev on X](https://x.com/omardulaimidev) to update your license accordingly.

**How do I activate my pro license?**

After receiving your license key from @omardulaimidev, follow the setup instructions provided. You can verify activation by running:

```bash
prisma-zod-generator license-check
```

**Do pro features require additional dependencies?**

Some pro features have optional peer dependencies:

- **Forms**: requires `react`, `react-hook-form`, `@hookform/resolvers`
- **SDK**: standalone, no additional deps
- **API Docs**: uses Express for mock server
- **Contracts**: requires `@pact-foundation/pact`, `jest`

Check each feature's documentation for specific requirements.

**Can I use pro features in open source projects?**

Pro licenses are per-developer, not per-project. If you have an active subscription, you can use pro features in any of your projects (including open source). For team/organization use, consider Business or Enterprise tiers.

***

## Core Features (Free)

**Why are select/include schemas missing?** Minimal mode disables them unconditionally to keep surface lean.

**Why didn’t my JSON config output path apply?** Generator block `output` attribute (if explicitly present) takes precedence.

**How do I exclude a field across all variants?** Use `globalExclusions` or legacy global array; variant-specific overrides for finer control.

**Can I only emit pure models?** Enable `pureModels`, disable variants or set all variant enabled flags false (custom mode) → pureModelsOnly heuristic.

**Why enums missing?** `emit.enums=false` was set; object/CRUD schemas referencing enums may fail.

**How do I control optional field validation?** Use `optionalFieldBehavior` to choose between `.nullish()` (default), `.optional()`, or `.nullable()` for optional Prisma fields.

**Where should I place my config file?** Config file paths are resolved relative to your Prisma schema file, not the project root. If your schema is at `prisma/schema.prisma` and you use `config = "./my-config.json"`, the generator will look for `prisma/my-config.json`.

**My config file isn't being found, what's wrong?** Check that:

1. The path in `config = "./path/to/config.json"` is relative to your schema file location
2. The file exists at the resolved path (generator will show the full resolved path in error messages)
3. The config file contains valid JSON
4. You're not using an empty config path (`config = ""` will throw an error)

# Logging & Debug Output

Minimal by default; enable debug for deep diagnostics.

## Default Output

Shows only warnings that affect emission (layout conflicts, minimal mode suppressions, config load fallback).

## Enable Debug

```bash
DEBUG_PRISMA_ZOD=1 npx prisma generate
# or
DEBUG=prisma-zod npx prisma generate
```

Add npm script:

```jsonc
"gen:debug": "DEBUG_PRISMA_ZOD=1 prisma generate"
```

## Warning Categories

- File layout conflicts (generator block vs JSON) – precedence reminder.
- Minimal mode suppression of select/include.
- Config load failure fallback.
- Validation warnings (filter combinations).

## Tips

- Keep logs with issues to speed triage.
- Disable after debugging to reduce CI noise.

# Naming Preset Map

| Preset              | filePattern        | schemaSuffix | typeSuffix | exportNamePattern       | legacyAliases |
| ------------------- | ------------------ | ------------ | ---------- | ----------------------- | ------------- |
| default             | \{Model}.schema.ts | Schema       | Type       | \{Model}\{SchemaSuffix} | false         |
| zod-prisma          | \{Model}.schema.ts | Schema       | Type       | \{Model}Schema          | true          |
| zod-prisma-types    | \{Model}.schema.ts | (empty)      | (empty)    | \{Model}                | true          |
| legacy-model-suffix | \{Model}.model.ts  | Model        | ModelType  | \{Model}Model           | false         |

Override tokens:

- `\{Model\}`, `\{model\}`, `\{camel\}`, `\{kebab\}`, `\{SchemaSuffix\}`, `\{TypeSuffix\}`

# PZG Pro CLI & API Reference

# PZG Pro API Reference

Complete API documentation for all PZG Pro features and CLI commands.

## 📋 Table of Contents

- [CLI Commands](#cli-commands)
- [Configuration API](#configuration-api)
- [License API](#license-api)
- [Policies API](#policies-api)
- [Server Actions API](#server-actions-api)
- [SDK Publisher API](#sdk-publisher-api)
- [Drift Guard API](#drift-guard-api)

## 🖥️ CLI Commands

### Core Commands

#### `prisma-zod-generator license-check`

Validate and display license information.

```bash
prisma-zod-generator license-check
```

**Sample Output:**

```
🔍 Checking PZG Pro license...

✅ Valid PZG Pro license found
📋 Plan: Business (business)
👥 Max Seats: 1
🆔 Customer ID: Name
📅 Valid Until: 2026-11-09T01:03:50.464Z
🌐 License verified with server

🚀 Ready to use PZG Pro features!
📚 Docs: /docs
💬 Support: https://github.com/omar-dulaimi/prisma-zod-generator/issues
```

#### `pzg-pro guard`

Run schema drift detection.

```bash
npx pzg-pro guard [options]
```

**Options:**

- `--schema <path>`: Path to `schema.prisma` (default: `./prisma/schema.prisma`)
- `--base <ref>`: Base git reference (default: `origin/main`)
- `--head <ref>`: Head git reference (default: `HEAD`)
- `--format <github|json|text>`: Output format (default: `github`)
- `--json`, `--text`, `--github`: Shortcuts for `--format`
- `--strict`: Treat warnings as breaking changes
- `--allowed-break <identifier>`: Whitelist a specific change (repeatable, see identifiers in the CLI output such as `model.User.field_removed`)
- `--help`: Show usage

**Examples:**

```bash
# Compare current branch to main (GitHub-style output)
npx pzg-pro guard --schema ./prisma/schema.prisma --base origin/main --format github

# Produce machine-readable JSON
npx pzg-pro guard --format json > drift-report.json

# Allow a known breaking change by identifier
npx pzg-pro guard --allowed-break model.User.field_removed
```

## 🔑 License API

### TypeScript API

```typescript
import {
  validateLicense,
  hasFeature,
  requireFeature,
  getLicenseStatus
} from 'prisma-zod-generator/lib/license';

// Validate license (non-throwing)
const license = await validateLicense(false);
if (license) {
  console.log(`Plan: ${license.plan}, Seats: ${license.maxSeats}`);
}

// Check feature availability
const hasPolicies = hasFeature(license, 'policies');

// Require feature (throws if not available)
await requireFeature('sdk-publisher', { userId: 'user-123' });

// Get license status
const status = await getLicenseStatus();
console.log('Valid:', status.valid);
```

> Set both `PZG_LICENSE_KEY` and `PZG_LICENSE_PUBLIC_KEY` in your environment before invoking the CLI so offline verification succeeds.

### License Object Schema

```typescript
interface License {
  key: string;                 // Full license key
  plan: 'starter' | 'professional' | 'business' | 'enterprise';
  validUntil: string;         // ISO date string
  maxSeats: number;           // Maximum developer seats
  cached: boolean;            // Whether loaded from cache
}

interface LicenseStatus {
  valid: boolean;
  plan?: string;
  cached?: boolean;
}
```

### Feature Availability

```typescript
// Available features by plan
const FEATURES = {
  'server-actions': ['starter', 'professional', 'business', 'enterprise'],
  'policies': ['professional', 'business', 'enterprise'],
  'sdk-publisher': ['professional', 'business', 'enterprise'],
  'drift-guard': ['professional', 'business', 'enterprise'],
  'postgres-rls-pack': ['professional', 'business', 'enterprise'],
  'performance-pack': ['professional', 'business', 'enterprise'],
  'contract-testing-pack': ['business', 'enterprise'],
  'form-ux': ['starter', 'professional', 'business', 'enterprise'],
  'api-docs-pack': ['business', 'enterprise'],
  'data-factories': ['business', 'enterprise'],
  'multi-tenant-kit': ['enterprise']
};
```

## 🛡️ Policies API

### Generated Policy Classes

Each model generates a policy class with validation methods:

```typescript
// Generated: ./generated/pzg/policies/user.ts
export class UserPolicies {
  static validateRead(data: any, context: PolicyContext): PolicyResult;
  static validateWrite(data: any, context: PolicyContext): PolicyResult;
  static validateDelete(context: PolicyContext): PolicyResult;
}

interface PolicyContext {
  userId?: string;
  role?: string;
  roles?: string[];
  tenantId?: string;
  sessionId?: string;
  [key: string]: any;
}

interface PolicyResult {
  allowed: boolean;
  data?: any;          // Filtered/modified data
  reason?: string;     // Reason for denial
}
```

### Redaction API

```typescript
// Generated: ./generated/pzg/redaction/index.ts
export class PIIRedactor {
  static redactForLogs(data: any, context?: PolicyContext): any;
  static maskField(value: string, type: 'email' | 'phone' | 'partial'): string;
  static hashField(value: string): string;
}
```

### Usage Example

```typescript
import { UserPolicies } from '@/generated/pzg/policies';
import { PIIRedactor } from '@/generated/pzg/redaction';

// Policy enforcement
const userData = { email: 'user@example.com', salary: 100000 };
const context = { userId: 'current-user', roles: ['user'] };

const readResult = UserPolicies.validateRead(userData, context);
if (readResult.allowed) {
  // Use readResult.data (salary may be filtered out)
  const safeData = readResult.data;
}

// PII redaction for logging
const logSafeData = PIIRedactor.redactForLogs(userData);
console.log('User updated:', logSafeData); // { email: 'u***@example.com', salary: 100000 }
```

## ⚡ Server Actions API

### Generated Server Actions

Each model generates CRUD actions:

```typescript
// Generated: ./src/server/actions/user/create.ts
export async function createUser(input: CreateUserInput): Promise<User>;
export async function updateUser(id: string, input: UpdateUserInput): Promise<User>;
export async function deleteUser(id: string): Promise<void>;
export async function findUsers(input?: FindUsersInput): Promise<User[]>;
```

### Generated React Hooks

```typescript
// Generated: ./src/server/hooks/useUser.ts
export function useCreateUser(): {
  create: (data: CreateUserInput) => Promise<User>;
  isPending: boolean;
  error: Error | null;
};

export function useUpdateUser(): {
  update: (id: string, data: UpdateUserInput) => Promise<User>;
  isPending: boolean;
  error: Error | null;
};

export function useUsers(input?: FindUsersInput): {
  data: User[] | undefined;
  isLoading: boolean;
  error: Error | null;
  refetch: () => void;
};
```

### Schema Types

```typescript
// Input schemas for validation
type CreateUserInput = z.infer<typeof CreateUserSchema>;
type UpdateUserInput = z.infer<typeof UpdateUserSchema>;
type FindUsersInput = z.infer<typeof FindUsersSchema>;
```

## 📦 SDK Publisher API

### Generated SDK Structure

```typescript
// Generated: ./packages/sdk/src/client.ts
export class APIClient {
  constructor(config: ClientConfig);

  // Model methods
  users: UserResource;
  posts: PostResource;
  // ... other models
}

interface ClientConfig {
  baseUrl: string;
  authToken?: string;
  timeout?: number;
  retries?: number;
}

class UserResource {
  create(data: CreateUserInput): Promise<User>;
  update(id: string, data: UpdateUserInput): Promise<User>;
  delete(id: string): Promise<void>;
  findMany(query?: FindUsersInput): Promise<User[]>;
  findUnique(id: string): Promise<User | null>;
}
```

### Error Handling

```typescript
// Generated error classes
export class APIError extends Error {
  status: number;
  code?: string;
  details?: any;
}

export class ValidationError extends APIError {
  field: string;
  message: string;
}

export class AuthenticationError extends APIError {}
export class AuthorizationError extends APIError {}
export class NotFoundError extends APIError {}
export class RateLimitError extends APIError {}
```

## 🚨 Drift Guard API

### Drift Detection Results

```typescript
interface DriftReport {
  summary: {
    safeChanges: number;
    breakingChanges: number;
    recommendations: string[];
  };
  changes: SchemaChange[];
  riskLevel: 'low' | 'medium' | 'high';
}

interface SchemaChange {
  type: 'field_added' | 'field_removed' | 'field_modified' | 'enum_modified';
  model: string;
  field?: string;
  before?: any;
  after?: any;
  breaking: boolean;
  description: string;
}
```

### Programmatic Usage

```typescript
import { analyzeSchemaDrift } from 'prisma-zod-generator/lib/drift-guard';

const report = await analyzeSchemaDrift({
  baseSchema: './prisma/schema.prisma',
  headSchema: './prisma/schema-new.prisma',
  config: {
    excludeFields: ['createdAt', 'updatedAt'],
    breakingThreshold: 'major'
  }
});

console.log(`${report.changes.length} changes detected`);
report.changes.forEach(change => {
  if (change.breaking) {
    console.error(`Breaking: ${change.description}`);
  }
});
```

## 📚 Type Definitions

### Common Types

```typescript
// Plan types
type PlanType = 'starter' | 'professional' | 'business' | 'enterprise';

// Feature types
type FeatureType =
  | 'server-actions'
  | 'policies'
  | 'sdk-publisher'
  | 'drift-guard'
  | 'postgres-rls-pack'
  | 'performance-pack'
  | 'contract-testing-pack'
  | 'form-ux'
  | 'api-docs-pack'
  | 'data-factories'
  | 'multi-tenant-kit';

// Generation options
interface GenerationOptions {
  outputPath?: string;
  schemaPath?: string;
  models?: string[];
  force?: boolean;
  dryRun?: boolean;
}
```

## 🐛 Error Types

```typescript
// License errors
class LicenseError extends Error {
  code: 'INVALID_LICENSE' | 'EXPIRED_LICENSE' | 'FEATURE_NOT_AVAILABLE';
  details?: any;
}

// Generation errors
class GenerationError extends Error {
  code: 'SCHEMA_PARSE_ERROR' | 'FILE_WRITE_ERROR' | 'VALIDATION_ERROR';
  file?: string;
  line?: number;
}

// Configuration errors
class ConfigError extends Error {
  code: 'INVALID_CONFIG' | 'MISSING_CONFIG' | 'CONFIG_PARSE_ERROR';
  field?: string;
}
```

***

**Need more details?** Check the [feature-specific documentation](../features/overview.md) or reach out via DM to [@omardulaimidev on X](https://x.com/omardulaimidev).

# Safety System

# Safety System

The prisma-zod-generator includes a comprehensive safety system that protects your source code from accidental deletion when using custom output paths.

:::tip
This safety system was introduced to solve [Issue #71](https://github.com/omar-dulaimi/prisma-zod-generator/issues/71) - a critical bug where the generator could delete entire directories containing user source code.
:::

## Overview

Prior to the safety system, the generator would delete **all contents** of the output directory before generating new schemas. This created a dangerous situation where users could accidentally lose their work by pointing the output to directories containing their source code.

```prisma title="schema.prisma - DANGEROUS (without safety system)"
generator zod {
  provider = "prisma-zod-generator"
  output   = "./src"  // ⚠️ This would delete all files in src/
}
```

## How It Works

The safety system uses a **hybrid manifest-based approach** with multiple layers of protection:

### 1. Path Validation

The system analyzes output paths for common patterns that suggest user source code:

#### ⚠️ Warned Paths (Common Source Directories)

- `src` - Source code directory
- `lib` - Library code
- `components` - React/Vue components
- `pages` - Next.js pages
- `app` - Application code
- `utils` - Utility functions
- `hooks` - React hooks
- `services` - Service layer code
- `api` - API endpoints

#### ❌ Blocked Paths (Project Directories)

Any directory containing these files is **completely blocked**:

- `package.json` - Node.js project
- `tsconfig.json` - TypeScript project
- `next.config.js` - Next.js project
- `vite.config.js` - Vite project
- `webpack.config.js` - Webpack project
- `rollup.config.js` - Rollup project
- `.gitignore` - Git repository
- `README.md` - Project documentation

### 2. Manifest Tracking

The generator creates and maintains a manifest file (`.prisma-zod-generator-manifest.json`) that tracks exactly which files and directories it creates:

```json title=".prisma-zod-generator-manifest.json"
{
  "version": "1.0",
  "generatorVersion": "1.16.6",
  "generatedAt": "2024-01-15T10:30:00.000Z",
  "outputPath": "/path/to/output",
  "files": [
    "User.schema.ts",
    "Post.schema.ts",
    "enums/Role.ts"
  ],
  "directories": [
    "enums",
    "objects"
  ]
}
```

### 3. Smart Cleanup

#### First Run (No Manifest)

Uses pattern detection to identify likely generated files:

- Analyzes file content for generator signatures
- Only removes files that contain generated code patterns
- Preserves files that don't match generator signatures

#### Subsequent Runs (With Manifest)

Uses precise manifest-based cleanup:

- Only removes files listed in the previous manifest
- Only removes directories that were created by the generator
- Never touches files not tracked in the manifest

### 4. Content Analysis

The system analyzes existing files to determine if they're user-generated:

- Checks file extensions (`.ts`, `.js`, `.tsx`, `.jsx`, etc.)
- Counts suspicious files that look like user code
- Blocks generation if too many user files are found (> 5 files)

## Safety Messages

### Warning Messages

When potentially risky paths are detected, you'll see helpful warnings:

```bash
⚠️  WARNING: Output directory "src" is a common source code directory name. 
Consider using a dedicated subdirectory like "src/generated" instead.

⚠️  WARNING: Output directory contains 3 files that may be user code: 
auth.service.ts, user.model.ts, config.ts. 
No manifest file found from previous generator runs.
```

### Error Messages

For dangerous configurations, generation is blocked with clear guidance:

```bash
❌ ERROR: Unsafe output path detected: Output directory contains project file "package.json".

To resolve this issue:
1. Use a dedicated directory for generated schemas (e.g., "./generated" or "./src/generated")
2. Or use a subdirectory within your source folder (e.g., "./src/zod-schemas")  
3. Avoid pointing directly to directories containing your source code

This safety check prevents accidental deletion of your work.
```

## Configuration Options

The safety system can be configured to match your project's needs. You can control safety behavior through configuration files, generator options, or environment variables.

### Safety Levels

Quick configuration using preset levels:

```json title="zod-generator.config.json"
{
  "safety": {
    "level": "strict"    // strict | standard | permissive | disabled
  }
}
```

```prisma title="schema.prisma"
generator zod {
  provider    = "prisma-zod-generator"
  safetyLevel = "permissive"
}
```

**Available levels:**

- **`strict`** - Maximum protection, blocks even small numbers of user files
- **`standard`** - Balanced protection (default)
- **`permissive`** - Warnings-heavy, minimal blocking
- **`disabled`** - No safety checks (⚠️ dangerous)

### Granular Controls

For fine-tuned control, use individual safety options:

```json title="zod-generator.config.json"
{
  "safety": {
    "enabled": true,
    "allowDangerousPaths": false,
    "allowProjectRoots": false, 
    "allowUserFiles": false,
    "skipManifest": false,
    "warningsOnly": false,
    "maxUserFiles": 5,
    "customDangerousPaths": ["modules", "widgets"],
    "customProjectFiles": ["custom.config.js"]
  }
}
```

#### Configuration Options

| Option                 | Type      | Default | Description                                               |
| ---------------------- | --------- | ------- | --------------------------------------------------------- |
| `enabled`              | boolean   | `true`  | Master switch for all safety features                     |
| `allowDangerousPaths`  | boolean   | `false` | Allow common source directories (src, lib, etc.)          |
| `allowProjectRoots`    | boolean   | `false` | Allow directories with project files (package.json, etc.) |
| `allowUserFiles`       | boolean   | `false` | Allow directories containing user files                   |
| `skipManifest`         | boolean   | `false` | Disable manifest tracking and cleanup                     |
| `warningsOnly`         | boolean   | `false` | Convert all errors to warnings (never block)              |
| `maxUserFiles`         | number    | `5`     | Maximum user files allowed before blocking                |
| `customDangerousPaths` | string\[] | `[]`    | Additional dangerous directory patterns                   |
| `customProjectFiles`   | string\[] | `[]`    | Additional project file patterns                          |

### Configuration Methods

#### Method 1: Config File (Recommended)

```json title="zod-generator.config.json"
{
  "output": "./generated",
  "safety": {
    "level": "standard",
    "allowDangerousPaths": true
  }
}
```

#### Method 2: Generator Block

```prisma title="schema.prisma"
generator zod {
  provider                   = "prisma-zod-generator"
  output                     = "./generated"
  safetyLevel               = "standard"
  safetyAllowDangerousPaths = true
}
```

#### Method 3: Environment Variables

```bash title=".env"
PRISMA_ZOD_SAFETY_LEVEL=permissive
PRISMA_ZOD_SAFETY_ALLOW_DANGEROUS_PATHS=true
PRISMA_ZOD_SAFETY_MAX_USER_FILES=10
```

### Configuration Precedence

Configurations are merged with this precedence (highest to lowest):

1. **Environment variables**
2. **Generator block options**
3. **Config file settings**
4. **Default values**

### Quick Configuration Examples

#### Allow Dangerous Paths

```json
{
  "safety": {
    "allowDangerousPaths": true
  }
}
```

#### Warnings Only Mode

```json
{
  "safety": {
    "warningsOnly": true
  }
}
```

#### Disable Safety (⚠️ Use with Caution)

```json
{
  "safety": {
    "enabled": false
  }
}
```

## Recommended Usage

### ✅ Safe Configurations

```prisma title="schema.prisma - RECOMMENDED"
generator zod {
  provider = "prisma-zod-generator"
  output   = "./generated"        // ✅ Dedicated directory
}
```

```prisma title="schema.prisma - ALSO SAFE"
generator zod {
  provider = "prisma-zod-generator"  
  output   = "./src/generated"    // ✅ Subdirectory in src
}
```

```prisma title="schema.prisma - ALSO SAFE"  
generator zod {
  provider = "prisma-zod-generator"
  output   = "./schemas"          // ✅ Schema-specific directory
}
```

### ⚠️ Configurations That Trigger Warnings

These will work but generate warnings encouraging better practices:

```prisma title="schema.prisma - WARNS BUT WORKS"
generator zod {
  provider = "prisma-zod-generator"
  output   = "./src"              // ⚠️ Common source directory
}
```

```prisma title="schema.prisma - WARNS BUT WORKS"
generator zod {
  provider = "prisma-zod-generator"
  output   = "./lib"              // ⚠️ Common library directory  
}
```

### ❌ Configurations That Are Blocked

These will prevent generation with error messages:

```prisma title="schema.prisma - BLOCKED"
generator zod {
  provider = "prisma-zod-generator"
  output   = "."                  // ❌ Project root
}
```

```prisma title="schema.prisma - BLOCKED"
generator zod {
  provider = "prisma-zod-generator"
  output   = "./my-app"           // ❌ If contains package.json
}
```

## Best Practices

### 1. Use Dedicated Directories

Always use directories specifically for generated code:

```
project/
├── src/                    # Your source code (protected)
│   ├── components/
│   ├── services/
│   └── utils/
├── generated/              # Generated schemas (safe to clean)
│   ├── schemas/
│   ├── enums/
│   └── objects/
├── prisma/
│   └── schema.prisma
└── package.json
```

### 2. Use Descriptive Directory Names

Make it obvious that directories contain generated code:

- `./generated`
- `./schemas`
- `./zod-schemas`
- `./prisma-zod`
- `./src/generated`
- `./lib/schemas`

### 3. Don't Point to Source Directories

Avoid pointing directly to directories containing your source code:

```prisma title="❌ AVOID"
output = "./src"
output = "./lib"  
output = "./components"
```

```prisma title="✅ PREFERRED"
output = "./src/generated"
output = "./lib/schemas"
output = "./generated"
```

## Troubleshooting

### Problem: "Unsafe output path detected" Error

**Cause**: You're trying to use a directory that contains project files or appears to contain user source code.

**Solution**:

1. Use a dedicated directory: `output = "./generated"`
2. Use a subdirectory: `output = "./src/generated"`
3. Remove project files from the target directory (if appropriate)

### Problem: Generator Warns About User Files

**Cause**: The output directory contains files that look like user code.

**Solutions**:

1. Use a different, empty directory for generated files
2. If the files are actually old generated files, delete them manually
3. If you're sure it's safe, the generator will still work (with warnings)

### Problem: Old Generated Files Not Cleaned Up

**Cause**: The manifest file might be missing or corrupted.

**Solution**:

1. Delete the `.prisma-zod-generator-manifest.json` file
2. Manually clean the output directory
3. Run the generator again to create a fresh manifest

### Problem: Need to Override Safety Checks

**Note**: There's currently no way to disable safety checks, and this is intentional. The safety system prevents data loss and encourages best practices.

**Alternative**: Use a dedicated subdirectory within your preferred location:

- Instead of `./src`, use `./src/generated`
- Instead of `./lib`, use `./lib/schemas`

## Technical Details

### Manifest File Structure

The manifest file tracks generation metadata:

```typescript
interface GeneratedManifest {
  version: string;              // Manifest format version
  generatorVersion?: string;    // Generator version that created it
  generatedAt: string;          // ISO timestamp
  outputPath: string;           // Absolute path to output directory
  files: string[];             // Relative paths of generated files
  directories: string[];       // Relative paths of generated directories
  singleFileMode?: boolean;    // Whether single-file mode was used
  singleFileName?: string;     // Name of single file (if applicable)
}
```

### Safety Validation Logic

The safety system uses this decision tree:

1. **Path Analysis**: Check directory name against known dangerous patterns
2. **Project Detection**: Look for project configuration files
3. **Content Analysis**: Count and analyze existing files
4. **Manifest Check**: Look for previous generation manifest
5. **Risk Assessment**: Combine all factors to determine safety level

### File Pattern Recognition

Generated files are identified by these signatures:

```typescript
const generatorSignatures = [
  '// Generated by prisma-zod-generator',
  '/* Generated by prisma-zod-generator',
  'from "@prisma/client"',
  'from "./objects/',
  'from "./enums/',
  'export const',
  'z.object({',
  'z.enum([',
  'PrismaClient',
  'Prisma.'
];
```

Files need multiple signature matches to be considered generated.

## Migration from Pre-Safety Versions

If you're upgrading from a version before the safety system:

### 1. Review Your Configuration

Check your current `output` setting:

```prisma title="schema.prisma"
generator zod {
  provider = "prisma-zod-generator"
  output   = "???"  // What's your current setting?
}
```

### 2. If Using a Dangerous Path

If your output points to `./src` or another source directory:

1. **Option A**: Move to a dedicated directory
   ```prisma
   generator zod {
     provider = "prisma-zod-generator"
     output   = "./generated"  // New safe location
   }
   ```

2. **Option B**: Use a subdirectory
   ```prisma
   generator zod {
     provider = "prisma-zod-generator" 
     output   = "./src/generated"  // Subdirectory in src
   }
   ```

3. Update your imports:
   ```typescript
   // Old imports
   import { UserSchema } from './User.schema';

   // New imports (Option A)
   import { UserSchema } from '../generated/User.schema';

   // New imports (Option B)  
   import { UserSchema } from './generated/User.schema';
   ```

### 3. If Receiving Warnings

If you see warnings but want to keep your current setup:

- The generator will still work
- Consider the suggestions in the warning messages
- Plan to migrate to a safer configuration when convenient

### 4. Clean Up Old Files

After changing your output path:

1. Delete old generated files from the previous location
2. Run the generator to create files in the new location
3. Update your imports to use the new paths

## Backwards Compatibility

The safety system is designed to be **completely backwards compatible**:

- ✅ Existing safe configurations continue to work unchanged
- ✅ No breaking changes to the generation process
- ✅ All existing features and options work as before
- ✅ Generated code format is identical

The only change is the addition of safety checks and the manifest file for tracking.

## Recipe Guides

For practical examples of configuring the safety system, see our recipe guides:

- **[Custom Safety Configuration](../recipes/safety-custom-configuration.md)** - Detailed guide to all configuration options
- **[Force Using Dangerous Paths](../recipes/safety-force-dangerous-path.md)** - How to safely use dangerous paths like `./src`
- **[Project Migration Guide](../recipes/safety-project-migration.md)** - Migrate existing projects to use safety system
- **[Disable Safety Completely](../recipes/safety-disable-completely.md)** - How to disable safety (with warnings about risks)

These recipes provide step-by-step instructions for common safety configuration scenarios.

***

:::info
The safety system represents a major improvement in user experience and data protection. It transforms the generator from a tool that could accidentally destroy your work into a safe, user-friendly utility that protects your code while providing helpful guidance.
:::

# Troubleshooting

# PZG Pro Troubleshooting Guide

Common issues, solutions, and debugging tips for PZG Pro features.

## 🔑 License Issues

### Invalid License Key Error

```
❌ Invalid PZG Pro license key. Please check your license key.
```

**Causes & Solutions:**

1. **Expired License**: Check expiration date with `npx prisma-zod-generator license-check`
2. **Wrong Environment Variable**: Ensure `PZG_LICENSE_KEY` is set correctly
3. **Corrupted Key**: Re-copy your license key from the purchase email
4. **Network Issues**: License validation requires internet connection

**Debugging Steps:**

```bash
# Check if license key is set
echo $PZG_LICENSE_KEY

# Validate license
npx prisma-zod-generator license-check

# Test with verbose output
DEBUG=pzg-pro:license npx prisma-zod-generator license-check
```

### License Validation Timeout

```
❌ License validation failed: Network timeout
```

**Solutions:**

1. Check internet connection
2. Configure corporate proxy if needed
3. Use offline cache mode (Enterprise feature)

### Code Tampering Warning

```
❌ PZG Pro code tampering detected. Pro features have been modified.
```

**Why it happens:** Integrity checks detected edits to the obfuscated Pro bundle (or the `src/pro` submodule).

**Fix:** Reinstall the published package (`pnpm install prisma-zod-generator@latest`) or reset the `src/pro` submodule to its shipped commit. Extend functionality via documented APIs instead of modifying bundled code.

## 🛡️ Policies & Redaction

### Policy Comments Not Recognized

**Symptom**: Policy annotations in schema comments are ignored

**Common Causes:**

1. **Wrong Comment Format**: Must use `/// @policy` or `/// @pii`
2. **Inline Comments**: Use separate comment lines, not inline with field
3. **Syntax Errors**: Check policy expression syntax

**Examples:**

```prisma
// ❌ Wrong: inline comment
model User {
  email String /// @pii email redact:logs  // This won't work
}

// ✅ Correct: separate line
model User {
  /// @pii email redact:logs
  email String
}

// ✅ Also correct: above field
model User {
  /// @policy read:role in ["admin"]
  /// @pii email mask:partial
  email String
}
```

### Policy Validation Errors

**Symptom**: Runtime errors when policies are applied

**Debugging:**

```bash
# Generate with debug output
DEBUG=pzg-pro:policies pnpm exec prisma generate

# Check generated policy files
ls prisma/generated/pro/policies/
cat prisma/generated/pro/policies/user.ts
```

### PII Redaction Not Working

**Check Configuration:** Add these keys to the `policies` JSON config (either inline in `schema.prisma` or the file referenced via `configPath`):

```json
{
  "enableRedaction": true,
  "piiFields": ["email", "phone", "ssn"]
}
```

## ⚡ Server Actions

### Server Action Import Errors

**Symptom**: Cannot resolve imports in generated actions

**Common Issues:**

1. **Wrong Output Path**: Check `serverActions.outputPath` in config
2. **Missing Dependencies**: Install required packages
3. **TypeScript Errors**: Run type check

**Solutions:**

```bash
# Install missing dependencies
npm install @tanstack/react-query next zod

# Check TypeScript errors
npx tsc --noEmit

# Regenerate after updating generator config
# serverActions = "{ \"outputPath\": \"./src/server\" }"
pnpm exec prisma generate
```

### React Hook Errors

**Symptom**: Hooks not working in components

**Requirements:**

```tsx
// ❌ Missing providers
function App() {
  return <CreateUserForm />;  // Hook will fail
}

// ✅ With providers
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <CreateUserForm />
    </QueryClientProvider>
  );
}
```

### "use server" Directive Missing

**Solution**: Regenerate server actions with latest version

```bash
rm -rf prisma/generated/pro/server-actions
pnpm exec prisma generate
```

## 📦 SDK Publisher

### SDK Build Failures

**Common Issues:**

1. **Missing TypeScript**: SDK requires TypeScript in target project
2. **Zod Version Mismatch**: Ensure compatible Zod versions
3. **Module Resolution**: Check package.json module settings

**Debug Steps:**

```bash
# Check generated SDK structure
ls packages/sdk/
cat packages/sdk/package.json

# Build manually
cd packages/sdk
npm run build

# Check for TypeScript errors
npm run type-check
```

### SDK Import Errors

**Symptom**: Cannot import generated SDK in client code

**Solutions:**

```bash
# Link for local development
cd packages/sdk
npm link

# In your client project
npm link @your-org/api-sdk

# Or publish to registry
cd packages/sdk
npm publish
```

## 🚨 Drift Guard

### CI Integration Issues

**Symptom**: Drift Guard workflow fails in GitHub Actions

**Common Issues:**

1. **Missing License**: Add `PZG_LICENSE_KEY` to GitHub Secrets
2. **Git Depth**: Need full git history for comparison
3. **Missing Dependencies**: Install PZG Pro in CI

**Working Workflow:**

```yaml
- uses: actions/checkout@v4
  with:
    fetch-depth: 0  # Important: full history

- name: Install dependencies
  run: npm ci

- name: Run Drift Guard
  env:
    PZG_LICENSE_KEY: ${{ secrets.PZG_LICENSE_KEY }}
  run: npx pzg-pro guard --schema=./prisma/schema.prisma --base origin/main --head HEAD --format github
```

### False Positive Breaking Changes

**Symptom**: Safe changes reported as breaking

**Solutions:**

1. **Update Config**: Exclude non-breaking fields
2. **Custom Rules**: Configure breaking change detection
3. **Manual Override**: Use repeated `--allowed-break <identifier>` flags for known migrations

```json
{
  "pro": {
    "driftGuard": {
      "excludeFields": ["createdAt", "updatedAt", "version"],
      "breakingChangeThreshold": "minor"
    }
  }
}
```

## 🏗️ General Issues

### Drift Guard Fails to Read Base Schema

**Symptom**: `fatal: path 'prisma/schema.prisma' does not exist in 'origin/main'`

- Ensure the workflow fetches full history (`fetch-depth: 0`).
- Confirm the `--base` ref contains the schema file.
- If the file moved, point Drift Guard at the new path via `--schema`.

### Out of Memory Errors

**Symptom**: Node.js heap out of memory during generation

**Solutions:**

```bash
# Increase memory limit
NODE_OPTIONS="--max-old-space-size=4096" pnpm exec prisma generate
```

### Slow Generation Performance

**Optimization Tips:**

1. **Limit Enabled Packs**: Disable `enable*` flags you don't need for the current run.
2. **Filter Models**: Use your existing generator filtering (e.g., `models = ["User","Post"]`) to skip unused models.
3. **Warm Node Modules**: Run `pnpm exec prisma generate` after dependencies are installed to avoid repeated cold starts.

### TypeScript Compilation Errors

**Common Issues:**

1. **Missing Types**: Install `@types/*` packages
2. **Version Conflicts**: Check TypeScript version compatibility
3. **Module Resolution**: Configure `tsconfig.json`

**Required tsconfig.json settings:**

```json
{
  "compilerOptions": {
    "strict": true,
    "moduleResolution": "bundler",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": [
    "generated/**/*",
    "src/**/*"
  ]
}
```

## 🐛 Debug Mode

### Enable Verbose Logging

```bash
# Global debug
DEBUG=pzg-pro:* pnpm exec prisma generate

# Specific modules
DEBUG=pzg-pro:license,pzg-pro:policies pnpm exec prisma generate

# File output
DEBUG=pzg-pro:* pnpm exec prisma generate 2> debug.log
```

### Common Debug Patterns

```bash
# License validation
DEBUG=pzg-pro:license npx prisma-zod-generator license-check

# Comment parsing
DEBUG=pzg-pro:parser pnpm exec prisma generate

# Code generation
DEBUG=pzg-pro:codegen pnpm exec prisma generate
```

## 📞 Getting Help

### Before Reaching Out

1. **Check License Status**: `npx prisma-zod-generator license-check`
2. **Update to Latest**: `npm install -D prisma-zod-generator@latest`
3. **Clear Cache**: `rm -rf node_modules/.cache/pzg`
4. **Review Logs**: Enable debug mode and check output

### Support Channels

- **GitHub Issues**: [Bug reports and feature requests](https://github.com/omar-dulaimi/prisma-zod-generator/issues)
- **Direct Support**: DM [@omardulaimidev on X](https://x.com/omardulaimidev) (Professional+ customers)

### Issue Template

When reporting issues, include:

```
**PZG Version**: 1.21.8
**Node Version**: 20.19.0
**License Plan**: Pro
**Feature**: Policies & Redaction

**Issue Description**:
[Describe the problem]

**Steps to Reproduce**:
1. Set up schema with...
2. Run command...
3. See error...

**Expected Behavior**:
[What should happen]

**Actual Behavior**:
[What actually happens]

**Debug Output**:
```

DEBUG=pzg-pro:\* pnpm exec prisma generate
\[paste output]

````

**Configuration**:
```json
[paste generator pzgPro block or the JSON referenced by configPath]
````

```

---

**Need immediate help?** Reach out via the direct support channel above for Professional+ customers.
```

# WhereUniqueInput Semantics

This page explains how `WhereUniqueInput` schemas are generated and validated, and how to enable an optional early validation check.

Overview

- Only unique selector fields are included at the top level (single-field uniques like `id` or `email`, plus named composite unique selectors like `userFolderPathIdx`).
- Top-level keys are optional by default to match Prisma’s runtime behavior.
- Composite uniqueness is enforced by nested selector schemas. For example, `{ adminFolderPathIdx: { adminId, path } }` requires both `adminId` and `path`.
- No cross-field superRefine is applied by default, to avoid false negatives on models with multiple composite unique keys.

Optional early validation

If you want to fail early when no selector is provided (reject `{}` at the Zod layer), enable the opt-in flag:

```jsonc
// zod-generator.config.json
{
  "validateWhereUniqueAtLeastOne": true
}
```

What it does

- Adds a minimal `.superRefine` to `*WhereUniqueInput` schemas that checks the presence of at least one top-level selector.
- Does not enforce “exactly one” (Prisma will still validate that constraint at runtime).
- Does not inspect nested composite fields; nested composite schemas already require all of their fields.

Examples

- Valid (one composite selector provided):

```ts
MediaFolderWhereUniqueInputObjectZodSchema.parse({
  adminFolderPathIdx: { adminId: 'A', path: '/root' },
});
```

- Invalid (composite selector present but empty): field-level errors from the nested schema:

```ts
MediaFolderWhereUniqueInputObjectZodSchema.parse({
  adminFolderPathIdx: {},
});
// → ZodError: adminFolderPathIdx.adminId and adminFolderPathIdx.path are required
```

- No selector provided:
  - With `validateWhereUniqueAtLeastOne=false` (default): parse may succeed; Prisma rejects later when used.
  - With `validateWhereUniqueAtLeastOne=true`: Zod rejects with “Provide at least one unique selector”.

Rationale

- Removing global superRefine avoids redundant and brittle cross-field logic.
- The nested composite schemas produce precise, actionable errors.
- For teams that want earlier feedback, the opt-in flag provides a safe, minimal check without re-implementing Prisma’s uniqueness rules.

# Upgrade Guide

This guide highlights actions needed when upgrading between notable versions.

## 1.x → 1.8.x

No breaking changes in generator output shape; internal docs site added. If you relied on undocumented script names for docs, update to the new `docs:*` scripts.

## Future (placeholder)

When a breaking change occurs, a section will be added here with migration steps and affected config fields.

# Upgrade from Free to Pro

# Migration Guide: Free to Pro

Complete step-by-step guide to upgrade from the free version of Prisma Zod Generator to PZG Pro.

## 📋 Overview

This guide will help you:

- Understand the differences between free and Pro versions
- Plan your migration strategy
- Execute the upgrade with minimal disruption
- Take advantage of new Pro features

**Estimated Time**: 30-60 minutes depending on your codebase size

## 🔍 Pre-Migration Assessment

### 1. Current Setup Analysis

First, understand your current setup:

```bash
# Check your current version
npm list prisma-zod-generator

# Review your Prisma schema
cat prisma/schema.prisma | grep -E "^model|^enum"

# Check generated files
ls -la prisma/generated/ # or wherever your schemas are generated
```

### 2. Compatibility Check

Ensure your environment meets Pro requirements (Prisma 7 baseline):

- **Node.js**: 20.19+ (22.x recommended)
- **Prisma**: 7.0+
- **TypeScript**: 5.4+ (5.9 recommended)
- **Zod**: 4.x recommended (>=3.25 supported)

### 3. Feature Planning

Decide which Pro features you want to use:

- ✅ **Server Actions**: Generate Next.js server actions
- ✅ **Policies & Redaction**: Field-level security and PII protection
- ✅ **SDK Publisher**: Generate client SDKs
- ✅ **Drift Guard**: Schema change detection in CI

## 🛒 Getting Your License

### 1. Choose Your Plan

Visit [the pricing page](/pricing) and select:

- **Starter ($69/year)** – 1 developer, Server Actions + Forms (CLI plan slug `starter`)
- **Professional ($199/year)** – up to 5 developers, security & governance suite (`professional`)
- **Business ($599/year)** – unlimited developers, platform toolkits (`business`)
- **Enterprise (Custom)** – unlimited developers, multi-tenant kit, roadmap partnership (`enterprise`)

### 2. Purchase & Download

After purchase, you'll receive:

- License key via email
- Access to Pro features
- Priority response targets (Business/Enterprise) and roadmap reviews (Enterprise)

### 3. Verify License

```bash
# Set your license key
export PZG_LICENSE_KEY=pzg_v2_your_license_key_here
export PZG_LICENSE_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAwRNEnFQJgBdNnwvnTTAPySp223shjXfioII2qMkqBFQ=\n-----END PUBLIC KEY-----'  # replace with the public key provided to you

# Verify it works
npx prisma-zod-generator license-check
```

## 🔧 Installation & Setup

### 1. Update Package

The Pro features are included in the same package:

```bash
# Update to latest version
npm update prisma-zod-generator

# Or with pnpm
pnpm update prisma-zod-generator

# Or with yarn
yarn upgrade prisma-zod-generator
```

### 2. Environment Configuration

Add your license key to environment variables:

```bash
# Option 1: Shell profile (.bashrc, .zshrc)
cat <<'EOF' >> ~/.bashrc
export PZG_LICENSE_KEY=pzg_v2_your_license_key_here
export PZG_LICENSE_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAwRNEnFQJgBdNnwvnTTAPySp223shjXfioII2qMkqBFQ=
-----END PUBLIC KEY-----'
EOF

# Option 2: Project .env file
cat <<'EOF' >> .env
PZG_LICENSE_KEY=pzg_v2_your_license_key_here
PZG_LICENSE_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAwRNEnFQJgBdNnwvnTTAPySp223shjXfioII2qMkqBFQ=
-----END PUBLIC KEY-----'
EOF
```

## 🏗️ Migration Strategy

### Strategy 1: Gradual Migration (Recommended)

Migrate one feature at a time to minimize risk:

1. **Week 1**: Set up license and basic configuration
2. **Week 2**: Add Server Actions to one model
3. **Week 3**: Add Policies to sensitive fields
4. **Week 4**: Set up Drift Guard in CI
5. **Week 5**: Generate SDK for external consumers

### Strategy 2: Full Migration

Migrate all features at once (for smaller projects):

1. Set up license and configuration
2. Generate all Pro features
3. Update application code
4. Test thoroughly
5. Deploy

### Strategy 3: Feature-by-Feature

Migrate based on business priorities:

1. **Security First**: Start with Policies & Redaction
2. **Developer Experience**: Add Server Actions
3. **API Stability**: Implement Drift Guard
4. **External Integrations**: Generate SDK

## 🔒 Adding Policies & Redaction

### 1. Identify Sensitive Fields

Review your Prisma schema for:

- **PII Data**: email, phone, ssn, address
- **Sensitive Data**: salary, medical info, financial data
- **Access-Controlled Data**: admin-only fields

### 2. Add Policy Comments

Update your Prisma schema with policy annotations:

```prisma
model User {
  id        String   @id @default(cuid())

  /// @pii email redact:logs mask:partial
  email     String   @unique

  /// @policy read:role in ["admin"]
  /// @pii sensitive hash:sha256
  salary    Int?

  /// @policy write:role in ["admin"]
  role      Role     @default(USER)

  createdAt DateTime @default(now())
}

model Post {
  id        String   @id @default(cuid())

  /// @policy write:userId eq context.userId
  title     String

  /// @policy read:published eq true OR role in ["admin"]
  content   String

  published Boolean  @default(false)
  userId    String
  user      User     @relation(fields: [userId], references: [id])
}
```

### 3. Generate Policies

Ensure `enablePolicies = true` in your `generator pzgPro` block, then run:

```bash
pnpm exec prisma generate
ls prisma/generated/pro/policies/
```

### 4. Integrate in Application

```typescript
// Example: API route with policy enforcement
import { UserPolicies } from '@/generated/pzg/policies';
import { PIIRedactor } from '@/generated/pzg/redaction';

export async function GET(request: Request) {
  const users = await prisma.user.findMany();

  // Apply read policies
  const filteredUsers = users.map(user => {
    const result = UserPolicies.validateRead(user, {
      userId: getCurrentUserId(),
      roles: getUserRoles()
    });
    return result.allowed ? result.data : null;
  }).filter(Boolean);

  // Redact for logs
  console.log('Users fetched:', PIIRedactor.redactForLogs(filteredUsers));

  return Response.json(filteredUsers);
}
```

## ⚡ Adding Server Actions

### 1. Generate Server Actions

Set `enableServerActions = true` in `schema.prisma`, then:

```bash
pnpm exec prisma generate
ls prisma/generated/pro/server-actions/
```

> Need only a subset of models? Use Prisma's generator filtering (`model` / `exclude`) so the Pro generator only processes the models you care about.

### 2. Review Generated Code

```bash
# Check generated server actions
ls src/server/actions/
ls src/server/hooks/
```

### 3. Update Your Components

Replace manual API calls with generated hooks:

**Before (Free Version):**

```tsx
// Manual API call
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);

const createUser = async (data) => {
  setLoading(true);
  try {
    const response = await fetch('/api/users', {
      method: 'POST',
      body: JSON.stringify(data)
    });
    const user = await response.json();
    // Handle success
  } catch (err) {
    setError(err);
  } finally {
    setLoading(false);
  }
};
```

**After (Pro Version):**

```tsx
// Generated hook with validation
import { useCreateUser } from '@/server/hooks/useUser';

const { create, isPending, error } = useCreateUser();

const handleSubmit = async (data) => {
  try {
    await create(data); // Automatic validation + policies
    // Success handled by hook
  } catch (err) {
    // Error handled by hook
  }
};
```

### 4. Add Required Dependencies

```bash
# Install React Query (for hooks)
npm install @tanstack/react-query

# Add to your app root
```

```tsx
// app/layout.tsx or pages/_app.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

export default function RootLayout({ children }) {
  return (
    <QueryClientProvider client={queryClient}>
      {children}
    </QueryClientProvider>
  );
}
```

## 📦 Generating SDK

### 1. Configure SDK Settings

Add the flag and JSON config to `generator pzgPro`:

```prisma
generator pzgPro {
  provider = "node ./node_modules/prisma-zod-generator/lib/cli/pzg-pro.js"
  output   = "./generated/pro"
  enableSDK = true
  sdk = "{ \"packageName\": \"@your-org/api-sdk\", \"version\": \"1.0.0\", \"outputPath\": \"./packages/sdk\", \"authHeader\": \"Authorization\", \"endpoints\": { \"baseUrl\": \"https://api.yourapp.com\", \"version\": \"v1\" } }"
}
```

### 2. Generate SDK

```bash
pnpm exec prisma generate
ls packages/sdk/
```

### 3. Publish SDK (Optional)

```bash
cd packages/sdk
npm run build
npm publish
```

### 4. Use SDK in Client Applications

```typescript
// Install in client projects
npm install @your-org/api-sdk

// Use in application
import { APIClient } from '@your-org/api-sdk';

const client = new APIClient({
  baseUrl: 'https://api.yourapp.com',
  authToken: 'your-auth-token'
});

const users = await client.users.findMany();
const newUser = await client.users.create({
  email: 'user@example.com',
  name: 'John Doe'
});
```

## 🚨 Setting Up Drift Guard

### 1. Create GitHub Workflow

```yaml
# .github/workflows/pzg-drift-guard.yml
name: PZG Drift Guard

on:
  pull_request:
    branches: [main]

jobs:
  schema-drift:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run Drift Guard
        env:
          PZG_LICENSE_KEY: ${{ secrets.PZG_LICENSE_KEY }}
          PZG_LICENSE_PUBLIC_KEY: ${{ secrets.PZG_LICENSE_PUBLIC_KEY }}
        run: npx pzg-pro guard --schema=./prisma/schema.prisma --base origin/main --head HEAD --format github
```

### 2. Add GitHub Secret

1. Go to your repository Settings > Secrets and variables > Actions
2. Add `PZG_LICENSE_KEY` with your license key value and `PZG_LICENSE_PUBLIC_KEY` with the PEM public key provided to you
3. Make sure it's marked as a secret (masked in logs)

### 3. Test Drift Guard

```bash
# Test locally against main
npx pzg-pro guard --schema=./prisma/schema.prisma --base main --head HEAD --format github

# Produce JSON output for scripts
npx pzg-pro guard --format json
```

## 🧪 Testing Your Migration

### 1. Validation Tests

Create tests to ensure your migration works:

```typescript
// tests/migration.test.ts
import { validateLicense } from 'prisma-zod-generator/lib/license';
import { UserPolicies } from '@/generated/pzg/policies';

describe('PZG Pro Migration', () => {
  test('license is valid', async () => {
    const license = await validateLicense(false);
    expect(license).toBeTruthy();
    expect(license.plan).toBeDefined();
  });

  test('policies are generated', () => {
    expect(UserPolicies.validateRead).toBeDefined();
    expect(UserPolicies.validateWrite).toBeDefined();
  });

  test('server actions exist', async () => {
    const { createUser } = await import('@/server/actions/user/create');
    expect(createUser).toBeDefined();
  });
});
```

### 2. Integration Tests

Test the full flow with real data:

```typescript
// tests/integration.test.ts
import { createUser } from '@/server/actions/user/create';
import { UserPolicies } from '@/generated/pzg/policies';

describe('Pro Features Integration', () => {
  test('server action with policies', async () => {
    // Test that server actions respect policies
    const userData = {
      email: 'test@example.com',
      name: 'Test User',
      role: 'ADMIN' // Should be blocked by policy
    };

    const context = { userId: 'regular-user', roles: ['user'] };
    const policyResult = UserPolicies.validateWrite(userData, context);

    expect(policyResult.allowed).toBe(false);
    expect(policyResult.reason).toContain('role');
  });
});
```

### 3. End-to-End Tests

Test the complete user journey:

```typescript
// e2e/pro-features.spec.ts
import { test, expect } from '@playwright/test';

test('user creation with validation', async ({ page }) => {
  await page.goto('/users/new');

  // Fill invalid data
  await page.fill('[name="email"]', 'invalid-email');
  await page.click('button[type="submit"]');

  // Should show validation error from Zod schema
  await expect(page.locator('.error')).toContainText('Invalid email');

  // Fill valid data
  await page.fill('[name="email"]', 'user@example.com');
  await page.fill('[name="name"]', 'John Doe');
  await page.click('button[type="submit"]');

  // Should redirect to users list
  await expect(page).toHaveURL('/users');
});
```

## 📊 Monitoring Your Migration

### 1. Performance Metrics

Monitor the impact of Pro features:

```typescript
// utils/monitoring.ts
export function trackPolicyPerformance() {
  const start = performance.now();

  return {
    end: () => {
      const duration = performance.now() - start;
      console.log(`Policy validation took ${duration}ms`);

      // Send to analytics
      if (typeof window !== 'undefined') {
        // Client-side tracking
      }
    }
  };
}
```

### 2. Error Tracking

Set up error monitoring for Pro features:

```typescript
// utils/error-tracking.ts
export function trackProError(error: Error, feature: string) {
  console.error(`PZG Pro ${feature} error:`, error);

  // Send to error tracking service
  if (process.env.NODE_ENV === 'production') {
    // Sentry, Bugsnag, etc.
  }
}
```

### 3. Usage Analytics

Track Pro feature adoption:

```typescript
// utils/analytics.ts
export function trackProFeatureUsage(feature: string, action: string) {
  // Track feature usage
  console.log(`PZG Pro feature used: ${feature}.${action}`);

  // Send to analytics service
}
```

## 🚀 Deployment Considerations

### 1. Environment Variables

Ensure license keys are properly set in all environments:

```bash
# Development
export PZG_LICENSE_KEY=pzg_v2_dev_key
export PZG_LICENSE_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAwRNEnFQJgBdNnwvnTTAPySp223shjXfioII2qMkqBFQ=\n-----END PUBLIC KEY-----'

# Staging
export PZG_LICENSE_KEY=pzg_v2_staging_key
export PZG_LICENSE_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAwRNEnFQJgBdNnwvnTTAPySp223shjXfioII2qMkqBFQ=\n-----END PUBLIC KEY-----'

# Production
export PZG_LICENSE_KEY=pzg_v2_prod_key
export PZG_LICENSE_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAwRNEnFQJgBdNnwvnTTAPySp223shjXfioII2qMkqBFQ=\n-----END PUBLIC KEY-----'
```

### 2. Build Process

Update your build scripts to generate Pro features:

```json
{
  "scripts": {
    "build": "pnpm exec prisma generate && next build",
    "generate:pro": "pnpm exec prisma generate",
    "prebuild": "pnpm exec prisma generate"
  }
}
```

### 3. CI/CD Pipeline

Update your deployment pipeline:

```yaml
# Deploy workflow
- name: Generate Pro Features
  env:
    PZG_LICENSE_KEY: ${{ secrets.PZG_LICENSE_KEY }}
    PZG_LICENSE_PUBLIC_KEY: ${{ secrets.PZG_LICENSE_PUBLIC_KEY }}
  run: |
    npm run generate:pro

- name: Build Application
  run: npm run build

- name: Run Tests
  run: npm test
```

## ✅ Post-Migration Checklist

### Immediate (Day 1)

- [ ] License validation works in all environments
- [ ] Generated code compiles without errors
- [ ] Basic functionality works (create, read, update, delete)
- [ ] CI/CD pipeline passes
- [ ] No breaking changes in existing functionality

### Short-term (Week 1)

- [ ] All team members can use Pro features
- [ ] Policies are enforcing correctly
- [ ] Server Actions work in production
- [ ] Drift Guard detects schema changes
- [ ] Error monitoring is set up

### Medium-term (Month 1)

- [ ] Performance is acceptable
- [ ] SDK is being used by external clients
- [ ] Policy violations are logged and monitored
- [ ] Business customers are comfortable with new features
- [ ] Documentation is updated

### Long-term (Quarter 1)

- [ ] ROI is positive (time saved, security improved)
- [ ] Advanced features are being utilized
- [ ] Integration with other tools is working
- [ ] Business plan adopters report productivity gains

## 🐛 Common Migration Issues

### Issue: "Invalid license key"

**Solution**:

- Check license key format and validity
- Ensure environment variable is set correctly
- Verify network connectivity for validation

### Issue: Generated files have import errors

**Solution**:

- Check output paths in configuration
- Ensure TypeScript can resolve imports
- Update tsconfig.json include paths

### Issue: Policies not enforcing

**Solution**:

- Verify policy syntax in schema comments
- Check that policies are being called in code
- Ensure policy context is provided correctly

### Issue: Server Actions not working

**Solution**:

- Install required dependencies (@tanstack/react-query)
- Set up QueryClient provider
- Check Next.js version compatibility

### Issue: CI/CD failures

**Solution**:

- Add license key to CI environment secrets
- Ensure full git history is available (fetch-depth: 0)
- Install all dependencies in CI

## 📞 Getting Help

### Documentation Resources

- [Pro Features Documentation](../features/overview.md)
- [API Reference](../reference/pro-cli.md)
- [Troubleshooting Guide](../reference/troubleshooting.md)

### Community Support

- [GitHub Issues](https://github.com/omar-dulaimi/prisma-zod-generator/issues)
- [Examples Repository](https://github.com/omar-dulaimi/pzg-examples)

### Premium Support

- **Direct Support**: DM [@omardulaimidev on X](https://x.com/omardulaimidev) (Professional, Business, Enterprise)
- **Direct Support**: Available for Business and Enterprise plans
- **Migration Assistance**: Custom migration help available

***

## 🎉 Welcome to PZG Pro!

Congratulations on successfully migrating to PZG Pro! You now have access to:

- **Enhanced Security**: Field-level policies and PII redaction
- **Better DX**: Generated Server Actions and React hooks
- **API Stability**: Schema drift detection and prevention
- **External Integration**: Auto-generated client SDKs
- **Priority Support**: Direct help when you need it

**Next Steps:**

1. Explore advanced Pro features
2. Join our Discord community
3. Share your success story
4. Consider upgrading as your team grows

Happy coding with PZG Pro! 🚀

# Usage Patterns

Common integration scenarios.

Tip: Need SDK clients, ready‑made forms, or a mock API server? See [Pro Features](./features/overview.md).

## tRPC Procedures

```ts
import { UserInputSchema, UserResultSchema } from './prisma/generated/schemas';

export const userRouter = t.router({
  create: t.procedure
    .input(UserInputSchema)
    .mutation(({ ctx, input }) => ctx.prisma.user.create({ data: input })),
});
```

## Express / Fastify

```ts
app.post('/users', (req, res) => {
  const parsed = UserInputSchema.parse(req.body);
  // ...
});
```

## Next.js Route Handler

```ts
export async function POST(req: Request) {
  const body = await req.json();
  const data = UserInputSchema.parse(body);
  return NextResponse.json(data);
}
```

## Form Validation

Use `safeParse` for user-facing error messaging.
