Prisma Zod Generator

repository·master·Indexed 21 days ago

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

A Prisma 2+ generator that automatically emits Zod validation schemas from a Prisma schema. It ensures runtime validation logic stays in sync with the database schema and Prisma Client, supporting CRUD operation wrappers, plain model schemas via pureModels, and custom validators through Prisma comments. The tool includes features for resolving TypeScript circular dependencies and is compatible with prisma-json-types-generator.

Tokens
111K
Snippets
313
Records
494
Agent score
70%

What's inside prisma-zod-generator

  1. Overview of PZG Pro Packs

    master

    While the core Prisma Zod Generator emits Zod schemas, the Pro version provides 'Packs' that generate additional layers of code from the same Prisma schema. These packs include:

    • Forms UX: Schema-driven React forms using Zod and React Hook Form (RHF).
    • SDK Publisher: Typed TypeScript and Python HTTP clients.
    • API Docs: OpenAPI specifications and a runnable mock server.
    • Policies: PII redaction and policy helpers via annotations.
    • Postgres RLS: PostgreSQL Row Level Security session context helpers.
    • Multi-Tenant: Server-side tenant validation, middleware, and extensions.
    • Performance: Streaming validators for large arrays.
    • Factories: Realistic test data builders.
    • Drift Guard: CI tools to detect breaking schema changes.
    • Contracts: Consumer/provider test definitions.
    • Server Actions: Typed actions validated with Zod.
  2. Core features of Prisma Zod Generator

    master

    The open-source version of the generator provides several schema generation and validation capabilities:

    Schema Generation

    • Multiple variants: Generates pure models, input schemas, and result schemas.
    • Generation modes: Supports Minimal (lean), Full (comprehensive), and Custom (fine-tuned) modes.
    • Field filtering: Ability to include or exclude specific fields using wildcard patterns.
    • Custom naming: Configure naming patterns for all generated schema types.
    • Output layouts: Choose between single-file or multi-file organization.
    • Custom Zod import: Use zodImportTarget or zodImportPath to point the generated z import to specific versions (e.g., zod/v3, zod/v4) or a custom instance (useful for i18n error maps).

    Advanced Validation

    • @zod annotations: Define inline validation rules via Prisma comments.
    • Metadata: Use @zod.meta({...}) or @zod.describe("...") on fields and models.
    • Special types: Support for Bytes, Decimal, BigInt, DateTime, and fully typed Json fields via @zod.import([...]).custom.use(...).
    • Relation handling: Smart defaults for nested objects.
    • Aggregate support: Support for count, min, max, avg, and sum operations.
    • Optionality: Configurable .nullish(), .optional(), or .nullable() behaviors.
  3. Distinguish between optionalFieldBehavior and the partial flag

    master

    It is important to distinguish between controlling Prisma's optionality and making entire variants partial:

    • optionalFieldBehavior: Specifically controls how Prisma-defined optional fields (e.g., String?) are handled in pure model schemas.
    • partial flag: A setting within variants that makes ALL fields in that variant optional, regardless of whether they were optional in the Prisma schema.

    Example of combining both in zod-generator.config.json:

    {
      "optionalFieldBehavior": "optional",
      "variants": {
        "input": {
          "enabled": true,
          "partial": true
        }
      }
    }
  4. Customize the Tenant Field name

    master

    The kit automatically detects tenant columns using common names like tenantId, organizationId, workspaceId, or companyId. If your schema uses a custom name (e.g., orgId or accountId), you must specify it using the tenantField key within the multiTenant JSON configuration in your schema.prisma generator block.

    Requirement: This requires version 2.4.1+. In earlier versions, tenantField was ignored, and validateTenantAccess() would throw No tenant validator found for model: <Model> if the field name was unrecognized.

    // Example of custom tenant field configuration
    generator pzgPro {
      provider = "node ./node_modules/prisma-zod-generator/lib/cli/pzg-pro.js"
      output = "./generated/pro"
      enableMultiTenant = true
      multiTenant = "{ \"tenantField\": \"orgId\" }"
    }
  5. How Prisma literal defaults are handled in Zod

    master

    Prisma @default(...) values with literal values are applied as .default(...) on pure model fields.

    Important Rules:

    • CRUD Inputs: Fields with database defaults are made .optional() in Create/Update schemas rather than carrying the default value. This prevents client-side defaults from conflicting with database logic.
    • Function Defaults: Defaults like @default(now()), @default(uuid()), @default(cuid()), and @default(autoincrement()) are not turned into Zod defaults. They are emitted as their plain base type in pure models and as .optional() in CRUD inputs.
    • Validation Order: The .default(...) is always appended after the validation chain (e.g., z.string().regex(...).default("value")).
    Prisma type@default(...)Emitted
    Int / Float / String / Boolean@default(1).default(1)
    BigInt@default(0).default(BigInt("0"))
    DateTimeliteral timestamp.default(new Date("..."))
    Json@default("[]").default([])
    Decimal@default(1).default(new Prisma.Decimal(1))
  6. Understand the generated directory layout

    master

    By default, the generator uses a multi-file layout. The structure is as follows:

    • helpers/: Contains helpers for Json or Decimal fields.
    • schemas/: The root for CRUD operation schemas (e.g., findManyUser.schema.ts).
    • schemas/enums/: Generated enums.
    • schemas/objects/: Generated object schemas.
    • schemas/results/: Result schemas (enabled in full mode).
    • schemas/variants/: Contains pure, input, and result variants.
    • schemas/models/: Contains pure models (only present if pureModels: true).
    • schemas/index.ts: A barrel file re-exporting all generated content.

    Single-file mode: If you set useMultipleFiles: false, all schemas are collapsed into a single file (e.g., prisma/generated/schemas.ts).

  7. Understand the fixed policy for Object Schemas (CRUD inputs)

    master

    Input object schemas (e.g., UserCreateInput.schema.ts) ignore the optionalFieldBehavior setting and follow a fixed policy to ensure compatibility with Prisma's API requirements:

    • Optional non-relation fields (scalars, enums, unions): Emitted as .optional().nullable() to allow both omission and explicit null.
    • Optional relation-shaped fields: Emitted as .optional() only. They reject null; you must omit the field to skip the relation.

    Example of Object Schema behavior:

    // Optional non-relation scalar
    name: z.string().optional().nullable()
    
    // Optional relation-shaped fields
    author: z.lazy(() => UserCreateNestedOneWithoutPostsInputObjectSchema).optional() 
    // ✅ undefined is ok
    // ❌ null is invalid; use omission instead
  8. Understand relation field behavior in result schemas

    master

    In result schemas, relation fields are typed as z.array(...).optional() because relations only appear when explicitly included in a query.

    • With pureModels enabled: The relation is typed against the related model's schema (e.g., z.array(TagSchema).optional()) via an import.
    • Without pureModels (or for self-relations/single-file mode): The generator falls back to z.array(z.unknown()).optional() to prevent cyclic reference errors.
  9. Resolve [TypeName] annotations to Zod schemas

    master

    When the generator encounters a [TypeName] annotation, it attempts to resolve it to a Zod schema using the following priority order:

    1. Explicit Map: If configured in typedJson.map[TypeName], it uses that exact expression.
    2. Module Import: It looks for <TypeName>{schemaSuffix} (where schemaSuffix defaults to Schema) imported from the path defined in typedJson.schemaModule.
    3. Fallback: If neither resolves, the field is left as its default type (e.g., Json) and a warning is recorded. This ensures compatibility with schemas intended only for PJTG.
  10. Understand the difference between PZG and prisma-json-types-generator

    master

    It is important to distinguish between prisma-zod-generator (PZG) and prisma-json-types-generator (PJTG) to choose the right tool for your needs:

    • prisma-json-types-generator (PJTG): Primarily used to type the Prisma Client itself by rewriting index.d.ts. It is a compile-time tool.
    • prisma-zod-generator (PZG): An additive tool that generates Zod schemas for validation. It does not type the Prisma Client.

    You do not need to switch from PJTG to use PZG; they serve different purposes (runtime validation vs. compile-time client typing).

  11. Choose a Generation Mode

    master

    The generator supports three distinct modes that control which models, variants, and operations are emitted. Choose a mode based on the balance you need between output richness and schema complexity.

    ModeModels defaultVariants defaultOperationsNotes
    fullall enabledall enabledall Prisma opsRichest output
    minimalall enabled unless disabledinput & pure enabled (result often off)Restricted core CRUD + findPrunes complex nested inputs, disables select/include; model selection behaves exactly like full mode
    customall enabled unless disabledrespect variants.*.enabledall unless filteredExplicit control