npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

typeorm-zod

v1.0.0

Published

Seamless integration between TypeORM entities and Zod validation using WeakMap-based metadata storage to prevent cross-entity pollution

Readme

typeorm-zod

Seamless integration between TypeORM entities and Zod validation using WeakMap-based metadata storage to prevent cross-entity pollution.

Features

  • Pollution-Free Metadata Storage: WeakMap-based metadata storage prevents entity metadata pollution
  • Inheritance-Aware Schema Generation: Includes base class properties automatically
  • Circular Dependency Safe: Proper handling of circular dependencies between entities
  • Property Name Conflict Resolution: Different entities can have properties with the same name
  • Automatic Schema Variants: Create/update/patch schema variants generated automatically
  • TypeORM Integration: Seamless integration with existing TypeORM decorators
  • Production Ready: Comprehensive error handling and validation

Code Generation (Codegen)

Requirements: The codegen CLI requires Bun to be installed:

curl -fsSL https://bun.sh/install | bash

To further enhance developer experience and ensure perfect type safety, typeorm-zod now includes a powerful Code Generation (Codegen) feature. This feature automatically generates centralized schema files, static TypeScript type definitions (DTOs), and validation helper functions directly from your decorated entities.

Benefits of Codegen:

  • Eliminates z.infer limitations: Provides true static type definitions for your DTOs, enabling full IDE autocompletion and compile-time type checking.
  • Single Source of Truth: All schemas, types, and validators are exported from a single generated file.
  • Automated Boilerplate: Reduces manual schema and type definition, especially for complex entities and multiple schema variants.
  • Seamless Integration: Generated types and validators are ready for use in API routes, service layers, and frontend applications.

How to Use Codegen:

  1. Create a Configuration File: Define typeorm-zod.codegen.config.ts (or .js) in your project root. This file specifies entity locations, output paths, and custom naming conventions.
  2. Run the Codegen CLI:
    • Run the CLI using bunx:
      bunx typeorm-zod-codegen
    • Alternatively, you can add a script to your package.json to run the codegen:
      "scripts": {
          "codegen": "typeorm-zod-codegen"
      }
      Then, you can execute it with Bun:
      bun run codegen
  3. Integrate into Workflow: Add the codegen command to your build pipeline (e.g., pre-build script) and consider using --watch mode during development.

For detailed configuration, examples, and advanced usage, please refer to the Code Generation Feature Documentation.

Quick Start

With typeorm-zod, you define validation once and get comprehensive schemas:

import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
import { ZodProperty, ZodColumn, createEntitySchemas } from 'typeorm-zod';
import { z } from 'zod';

@Entity()
export class User {
    @PrimaryGeneratedColumn('uuid')
    @ZodProperty(z.string().uuid())
    id: string;

    @ZodColumn({ type: 'varchar', length: 255 }, z.string().min(1).max(255))
    name: string;

    @ZodColumn({ type: 'varchar', length: 255, unique: true }, z.string().email())
    email: string;

    @ZodColumn({ type: 'int', nullable: true }, z.number().int().positive().nullable())
    age?: number;
}

// Generate comprehensive schema collection
const userSchemas = createEntitySchemas(User);
// Available: full, create, update, patch, query schemas

Installation

npm install typeorm-zod
# or
bun add typeorm-zod
# or
yarn add typeorm-zod
# or
pnpm add typeorm-zod

Inheritance Support

import { CreateDateColumn, UpdateDateColumn } from 'typeorm';

// Base entity class
export abstract class AppEntity {
    @PrimaryGeneratedColumn('uuid')
    @ZodProperty(z.string().uuid())
    id: string;

    @CreateDateColumn()
    @ZodProperty(z.date())
    createdAt: Date;

    @UpdateDateColumn()
    @ZodProperty(z.date())
    updatedAt: Date;
}

// Child entity inherits validation
@Entity()
export class Product extends AppEntity {
    @ZodColumn({ type: 'varchar', length: 255 }, z.string().min(1))
    name: string;

    @ZodColumn({ type: 'decimal', precision: 10, scale: 2 }, z.number().positive())
    price: number;
}

// Automatically includes base class properties
const productSchemas = createEntitySchemas(Product);
// Schemas include: id, createdAt, updatedAt, name, price

Available Schema Variants

The createEntitySchemas() function generates 5 schema variants:

const userSchemas = createEntitySchemas(User);

// Full schema - includes all fields
userSchemas.full;

// Create schema - omits id, createdAt, updatedAt, deletedAt
userSchemas.create;

// Update schema - id required, everything else optional
userSchemas.update;

// Patch schema - all fields optional
userSchemas.patch;

// Query schema - all fields optional (for filtering)
userSchemas.query;

Per-Property Schema Control

Use the enhanced @ZodProperty decorator to exclude fields from specific schema variants:

@Entity()
export class Note extends AppEntity {
    @Column('varchar', { length: 500 })
    @ZodProperty(z.string().min(1).max(500))
    title: string;

    @Column('longtext')
    @ZodProperty(z.string())
    content: string;

    // Auto-managed version field - exclude from create/update/patch
    @VersionColumn()
    @ZodProperty({
        schema: z.number().int().min(0),
        skip: ['create', 'update', 'patch']
    })
    version: number;

    // Auto-generated timestamp - exclude only from create
    @UpdateDateColumn()
    @ZodProperty({
        schema: z.date(),
        skip: ['create']
    })
    updatedAt: Date;
}

// Generated schemas automatically respect skip settings:
const noteSchemas = createEntitySchemas(Note);

// noteSchemas.create: { title, content } - no version or updatedAt
// noteSchemas.update: { id, title?, content?, updatedAt? } - no version  
// noteSchemas.full: { id, title, content, version, createdAt, updatedAt } - all fields

Advanced Usage with Custom Options

const userSchemas = createEntitySchemas(User, {
    // Additional fields to omit from create schema
    omitFromCreate: ['internalId'],
    
    // Additional fields to omit from update schema
    omitFromUpdate: ['email'], // Email cannot be updated
    
    // Custom field transformations
    transforms: {
        email: (schema) => schema.toLowerCase().trim(),
        age: (schema) => schema.min(13).max(120) // Add age constraints
    }
});

Type Inference

All TypeScript types are automatically inferred:

type CreateUserDto = z.infer<typeof userSchemas.create>;
type UpdateUserDto = z.infer<typeof userSchemas.update>;
type UserQueryDto = z.infer<typeof userSchemas.query>;

// Perfect type safety
const createUser = (data: CreateUserDto) => {
    // data.name is string
    // data.email is string | undefined  
    // data is fully typed and validated
};

API Route Validation

import { Hono } from 'hono';
import { zValidator } from '@hono/zod-validator';

const app = new Hono();

// Create user endpoint
app.post('/users', 
    zValidator('json', userSchemas.create),
    async (c) => {
        const userData = c.req.valid('json');
        // userData is fully typed and validated
        
        const user = userRepository.create(userData);
        await userRepository.save(user);
        
        return c.json({ success: true, user });
    }
);

// Update user endpoint  
app.patch('/users/:id',
    zValidator('json', userSchemas.patch),
    async (c) => {
        const updateData = c.req.valid('json');
        const userId = c.req.param('id');
        
        await userRepository.update(userId, updateData);
        return c.json({ success: true });
    }
);

API Reference

Decorators

@ZodProperty(zodSchema) or @ZodProperty({ schema, skip? })

Adds Zod validation to any property with optional schema control:

Basic Usage:

@ZodProperty(z.string().min(1).max(100))
name: string;

@ZodProperty(z.number().int().positive())
age: number;

@ZodProperty(z.string().email().optional())
email?: string;

Advanced Usage with Per-Property Schema Control:

// Skip validation for specific schema variants
@ZodProperty({
    schema: z.number().int().min(0),
    skip: ['create', 'update', 'patch'] // Exclude from these schemas
})
version: number; // Auto-managed by TypeORM @VersionColumn

@ZodProperty({
    schema: z.date(),
    skip: ['create'] // Only exclude from create schema
})
updatedAt: Date; // Auto-managed, but allow in update/patch

@ZodProperty({
    schema: z.string().uuid(),
    skip: ['create', 'update'] // Only include in full, patch, and query
})
id: string; // Primary key - exclude from create/update

Schema Variants:

  • 'full' - Complete entity schema with all fields
  • 'create' - For creating new entities (typically excludes auto-generated fields)
  • 'update' - For updating existing entities (id required, others optional)
  • 'patch' - For partial updates (all fields optional)
  • 'query' - For filtering/searching (all fields optional)

@ZodColumn(columnOptions, zodSchema)

Combines TypeORM @Column() with Zod validation:

@ZodColumn(
  { length: 255, nullable: false },
  z.string().min(1).max(255)
)
name: string;

// Equivalent to:
@Column({ length: 255, nullable: false })
@ZodProperty(z.string().min(1).max(255))
name: string;

Schema Generation

createEntitySchemas<T>(entityClass, options?)

Generates all schema variants from an entity class.

Parameters:

  • entityClass: Entity class constructor
  • options?: Schema generation options

Returns: EntitySchemas<T> with full, create, update, patch, query schemas.

createCreateSchema<T>(entityClass, options?)

Generates only the create schema (convenience function).

createUpdateSchema<T>(entityClass, options?)

Generates only the update schema (convenience function).

Options

interface SchemaGenerationOptions {
  /** Additional fields to omit from create schema */
  omitFromCreate?: string[];
  
  /** Fields to omit from update schema */
  omitFromUpdate?: string[];
  
  /** Custom field transformations */
  transforms?: Record<string, (schema: z.ZodTypeAny) => z.ZodTypeAny>;
}

Advanced Usage

Custom Transforms

const UserSchemas = createEntitySchemas(User, {
  transforms: {
    // Transform email field for create schema
    email: (schema) => schema.transform(email => email.toLowerCase())
  }
});

Migration Strategy

For existing projects, you can migrate gradually:

  1. Add decorators to existing entities:
// Before
@Column()
name: string;

// After  
@ZodProperty(z.string().min(1).max(255))
@Column()
name: string;
  1. Generate schemas and replace manual ones:
// Replace manual schemas
const UserSchemas = createEntitySchemas(User);
export const CreateUserSchema = UserSchemas.create;
  1. Remove duplicate types and use inferred ones:
// Remove manual type definitions
type CreateUserDto = z.infer<typeof CreateUserSchema>;

Benefits

  • Zero Duplication - Single source of truth
  • Type Safety - Perfect TypeScript integration
  • Validation - Automatic request validation
  • Productivity - Write less, get more
  • Maintainability - Update once, everywhere benefits
  • Migration Friendly - Works with existing projects

Requirements

  • TypeORM >= 0.3.0
  • Zod >= 4.0.0
  • TypeScript >= 5.0.0
  • reflect-metadata package

License

MIT © Angel S. Moreno

Contributing

Contributions are welcome! Please read our Contributing Guidelines to get started.

Code of Conduct

This project follows a Code of Conduct. Please read it to understand the expected behavior when participating in this project.