@libar-dev/zod-convex-gen
v0.1.0
Published
Build-time Zod to Convex validator generator for eliminating runtime bundle size
Maintainers
Readme
@libar-dev/zod-convex-gen
Build-time Zod to Convex validator generator - eliminates Zod from runtime bundle
The Problem
Convex applications using Zod at runtime can exceed the 64MB memory limit. The Zod library adds ~55-62MB of overhead, leaving minimal room for business logic.
The Solution
This package converts Zod schemas to pure Convex validators at build time, eliminating Zod from the runtime bundle entirely.
Results: 90% memory reduction (62MB → 10-15MB) with 100% type safety maintained.
Quick Start
1. Install
npm install --save-dev @libar-dev/zod-convex-gen tsx
# or: pnpm add -D @libar-dev/zod-convex-gen tsxRequires: Zod 4.x, Node.js 20+
2. Create Schema
// src/table-schemas/users.ts
import { z } from 'zod';
export const UsersTableSchema = z.object({
email: z.string().email(),
name: z.string(),
role: z.enum(['admin', 'user', 'guest']),
createdAt: z.number(),
}).strict();
// Export type alias for hybrid pattern
export type User = z.infer<typeof UsersTableSchema>;3. Generate Validators
npx zod-convex-genCreates convex/generatedValidators/users.ts:
// AUTO-GENERATED - DO NOT EDIT
import { v } from 'convex/values';
export const usersFields = {
email: v.string(),
name: v.string(),
createdAt: v.float64(),
};
export const usersEnums = {
role: v.union(v.literal('admin'), v.literal('user'), v.literal('guest')),
};
export const usersObject = v.object({ ...usersFields, ...usersEnums });
export const usersArray = v.array(usersObject);4. Use in Convex Schema
// convex/schema.ts
import { defineSchema, defineTable } from 'convex/server';
import { usersFields, usersEnums } from './generatedValidators/users';
export default defineSchema({
users: defineTable({ ...usersFields, ...usersEnums })
.index('by_email', ['email']),
});CLI Reference
Commands
| Command | Description |
|---------|-------------|
| generate | Generate validators (default) |
| clean | Remove generated files |
| info | Show configuration and loaders |
| init | Create sample config file |
Options
| Option | Description | Default |
|--------|-------------|---------|
| -i, --input <path> | Input directory | src/table-schemas |
| -o, --output <path> | Output directory | convex/generatedValidators |
| -w, --watch | Watch mode | false |
| -p, --pattern <pattern> | Schema export pattern | *TableSchema |
| --loader <name> | TypeScript loader | tsx |
| --dry-run | Validate without writing | false |
| --no-format | Skip prettier formatting | false |
| -v, --verbose | Verbose output | false |
Examples
# Development with auto-regeneration
npx zod-convex-gen --watch
# Custom directories
npx zod-convex-gen -i src/schemas -o convex/validators
# Validation only (CI)
npx zod-convex-gen --dry-run
# Clean stale files
npx zod-convex-gen clean --stale --forceConfiguration
Zero Configuration
Works out of the box with these conventions:
- Input:
src/table-schemas/ - Output:
convex/generatedValidators/ - Schema pattern: exports ending with
TableSchema
Config File
Create zod-convex-gen.json or use npx zod-convex-gen init:
{
"input": ["src/table-schemas", "src/validation-schemas"],
"output": "convex/generatedValidators",
"schemaPattern": "*TableSchema",
"tableNameTransform": "camelCase",
"format": true,
"preserveDirectoryStructure": true,
"maxInlineDepth": 2,
"extractUnions": true
}All Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| input | string \| string[] | src/table-schemas | Input directories |
| output | string | convex/generatedValidators | Output directory |
| schemaPattern | string | *TableSchema | Export name pattern |
| tableNameTransform | string | camelCase | Name transform (camelCase, kebab-case, snake_case, none) |
| format | boolean | true | Prettier formatting |
| outputMode | string | multiple | multiple or single file |
| preserveDirectoryStructure | boolean | true | Mirror input structure |
| maxInlineDepth | number | 2 | Max nesting before extraction |
| extractUnions | boolean | true | Extract nested unions |
| includeTimestamp | boolean | false | Add timestamp to headers |
| exclude | string[] | ['*.test.ts', '*.spec.ts'] | Files to exclude |
| minFieldsForExtraction | number | 3 | Min fields to trigger extraction |
| loader | string | tsx | TypeScript loader |
| verbosity | string | quiet | silent, quiet, normal, verbose |
Troubleshooting
"No schemas found"
Ensure schemas end with
TableSchema:export const UsersTableSchema = z.object({...}); // ✅ export const UserSchema = z.object({...}); // ❌Verify input directory exists:
ls src/table-schemas/Check exports are named (not default):
export const UsersTableSchema = ... // ✅ const UsersTableSchema = ... // ❌ (missing export)
"Cannot load TypeScript file"
Install a TypeScript loader:
npm install --save-dev tsx # Recommended
# or: ts-node, esbuild, @swc/coreFiles not updating
Use watch mode during development:
npx zod-convex-gen --watchType errors after generation
Follow build order:
npx zod-convex-gen # 1. Generate validators
npx convex codegen # 2. Generate Convex types
npx tsc --noEmit # 3. TypeScript validationTS2589 "Type instantiation excessively deep"
This generator prevents most TS2589 errors by:
- Generating pre-composed validators (
*Array,*Record,*OrNull) - Auto-extracting deeply nested structures
To use correctly:
// ❌ WRONG - inline construction causes TS2589
returns: v.array(v.object(mySchemaFields))
// ✅ CORRECT - use pre-composed validator from generated output
returns: mySchemaArray
// ❌ WRONG - explicit Promise type conflicts with returns validator
handler: async (ctx, args): Promise<MyType> => { ... }
// ✅ CORRECT - let validator infer type
handler: async (ctx, args) => { ... }
// ❌ WRONG - variable annotation conflicts
const result: MyType = await ctx.runMutation(...);
// ✅ CORRECT - no annotation
const result = await ctx.runMutation(...);If errors persist, reduce maxInlineDepth in config:
{ "maxInlineDepth": 1 }See TS2589 Usage Guide for complete patterns including helper function anti-patterns, test helpers, and diagnostic commands.
Documentation
- Architecture & Two-Stage Conversion
- TS2589 Usage Guide
- Advanced Features
- Patterns & Best Practices
- API Reference
License
MIT
