Skip to content

yassinrais/prisma-to-zod-v4

Repository files navigation

NPM Contributors Forks Stargazers Issues MIT License


Logo

Zod Prisma

A custom prisma generator that creates Zod schemas from your Prisma model.
Explore the docs »

View Demo · Report Bug · Request Feature

Table of Contents

  1. About The Project
  2. Getting Started
  3. Usage
  4. Examples
  5. Roadmap
  6. Contributing
  7. License
  8. Contact

About The Project

I got tired of having to manually create Zod schemas for my Prisma models and of updating them everytime I made schema changes. This provides a way of automatically generating them with your prisma

Built With

Getting Started

To get a local copy up and running follow these simple steps.

Prerequisites

This project uses pnpm.

Installation

  1. Ensure your tsconfig.json enables the compiler's strict mode. Zod requires it and so do we, you will experience TS errors without strict mode enabled

  2. Add prisma-to-zod-v4 as a dev dependency

    pnpm add -D prisma-to-zod-v4
  3. Add the prisma-to-zod-v4 generator to your schema.prisma

    generator zod {
    		provider = "prisma-to-zod-v4"
    
    		// Output directory for generated Zod schemas
    		output = "./zod" // default
    
    		// Relation model generation
    		relationModel = true        // default: generate both plain and related models
    		// relationModel = "default" // generate only related models (no plain models)
    		// relationModel = false     // disable related model generation
    
    		// Naming conventions
    		modelCase   = "PascalCase" // default: UserModel, PostModel
    		// modelCase = "camelCase" // userModel, postModel
    
    		// Suffix appended to generated Zod schemas
    		modelSuffix = "Model" // default
    
    		// Zod import path
    		zodImportPath = "zod" // default: import from 'zod'
    		// zodImportPath = "zod/v4" // import from 'zod/v4'
    		// zodImportPath = "zod/v3" // import from 'zod/v3'
    
    		// Decimal handling
    		// useDecimalJs = false // default: represent Prisma Decimal as number
    		useDecimalJs  = true  // represent Prisma Decimal using Decimal.js (matches Prisma behavior)
    
    		// Enable coercion for input schemas (e.g. strings → numbers, dates)
    		useCoerce = true
    
    		// Custom imports for generated schemas
    		imports = null // default: no additional imports
    
    		// JSON field nullability behavior
    		// See: https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-by-null-values
    		prismaJsonNullability = true  // default: follow Prisma's JSON nullability rules
    		// prismaJsonNullability = false // allow null assignment to optional JSON fields
    
    		// String validation options
    		useMinLength = true  // default: false - adds .min(1) to required string fields
    		useTrimStrings = true  // default: false - adds .trim() to required string fields (requires useMinLength)
    		usePrefaultEmptyString = true  // default: false - adds .prefault("") to handle undefined values (requires useTrimStrings and useMinLength)
    	}
  4. Run npx prisma generate or pnpm prisma generate to generate your zod schemas

  5. Import the generated schemas form your selected output location

Usage

JSDoc Generation

Rich-comments in the Prisma schema will be transformed into JSDoc for the associated fields:

Note: make sure to use a triple-slash. Double-slash comments won't be processed.

model Post {
  /// The unique identifier for the post
  /// @default {Generated by database}
  id String @id @default(uuid())

  /// A brief title that describes the contents of the post
  title String

  /// The actual contents of the post.
  contents String
}

Generated code:

export const PostModel = z.object({
	/**
	 * The unique identifier for the post
	 * @default {Generated by database}
	 */
	id: z.string().uuid(),
	/**
	 * A brief title that describes the contents of the post
	 */
	title: z.string(),
	/**
	 * The actual contents of the post.
	 */
	contents: z.string(),
})

Extending Zod Fields

You can also use the @zod keyword in rich-comments in the Prisma schema to extend your Zod schema fields:

model Post {
  id String @id @default(uuid()) /// @zod.uuid()

  /// @zod.max(255, { message: "The title must be shorter than 256 characters" })
  title String

  contents String /// @zod.max(10240)
}

Generated code:

export const PostModel = z.object({
	id: z.string().uuid(),
	title: z.string().max(255, { message: 'The title must be shorter than 256 characters' }),
	contents: z.string().max(10240),
})

Importing Helpers

Sometimes its useful to define a custom Zod preprocessor or transformer for your data. prisma-to-zod-v4 enables you to reuse these by importing them via a config options. For example:

generator zod {
  provider      = "zod-prisma"
  output        = "./zod"
  imports 		  = "../src/zod-schemas"
}

model User {
  username	String /// @zod.refine(imports.isValidUsername)
}

The referenced file can then be used by simply referring to exported members via imports.whateverExport. The generated zod schema files will now include a namespaced import like the following.

import * as imports from '../../src/zod-schemas'

Custom Zod Schema

In conjunction with this import option, you may want to utilize an entirely custom zod schema for a field. This can be accomplished by using the special comment directive @zod.custom(). By specifying the custom schema within the parentheses you can replace the autogenerated type that would normally be assigned to the field.

For instance if you wanted to use z.preprocess

Zod Version Selection

You can control which version of Zod to import from using the zodImportPath configuration option. This is useful when working with multiple versions of Zod or when the library exports version-specific entry points.

generator zod {
  provider      = "prisma-to-zod-v4"
  zodImportPath = "zod"    // default: import * as z from 'zod'
  // zodImportPath = "zod/v4" // import * as z from 'zod/v4'
  // zodImportPath = "zod/v3" // import * as z from 'zod/v3'
}

Generated imports:

  • zodImportPath = "zod"import * as z from 'zod'
  • zodImportPath = "zod/v4"import * as z from 'zod/v4'
  • zodImportPath = "zod/v3"import * as z from 'zod/v3'

String Validation Options

prisma-to-zod-v4 provides three configuration options to enhance string field validation:

useMinLength

Adds .min(1) validation to required string fields, ensuring they are not empty strings.

model User {
  name String // required field
  bio  String? // optional field
}

With useMinLength = true:

export const UserModel = z.object({
	name: z.string().min(1), // required → gets .min(1)
	bio: z.string().nullish(), // optional → no .min(1)
})

useTrimStrings

Adds .trim() to required string fields when used with useMinLength. This automatically trims whitespace before validation.

With useMinLength = true and useTrimStrings = true:

export const UserModel = z.object({
	name: z.string().trim().min(1),
	bio: z.string().nullish(),
})

usePrefaultEmptyString

Adds .prefault("") to handle undefined values. When enabled (requires both useMinLength and useTrimStrings), undefined values are converted to empty strings before processing. This ensures consistent behavior when validation fails - the value will be "" instead of undefined.

With all three options enabled:

export const UserModel = z.object({
	name: z.string().trim().min(1).prefault(''),
	bio: z.string().nullish(),
})

Behavior comparison:

// Without prefault:
schema.safeParse(undefined) // { success: false, data: undefined }

// With prefault:
schema.safeParse(undefined) // { success: false } but undefined → "" in processing

Note: usePrefaultEmptyString only works when both useMinLength and useTrimStrings are enabled.

JSON Fields

JSON fields in Prisma disallow null values. This is to disambiguate between setting a field's value to NULL in the database and having a value of null stored in the JSON. In accordance with this prisma-to-zod-v4 will default to disallowing null values, even if your JSON field is optional.

If you would like to revert this behavior and allow null assignment to JSON fields, you can set prismaJsonNullability to false in the generator options.

Examples

For examples, please refer to the Examples Directory or the Functional Tests

Roadmap

See the open issues for a list of proposed features (and known issues).

Contributing

Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

License

Distributed under the MIT License. See LICENSE for more information.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors