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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@naviary-sanctuary/schema-gen

v0.3.0

Published

Automatically generate validation schemas from TypeScript class definitions

Downloads

210

Readme

schema-gen

CLI tool to automatically generate validation schemas from TypeScript class definitions

Why?

When building APIs with validation, you often define classes for your DTOs (or domain models) and then have to manually write validation schemas:

// 1. You write your class
class User {
  id: string;
  name: string;
  email: string;
  createdAt: Date;
}

// 2. Then you manually write the schema again
const userSchema = t.Object({
  id: t.String(),
  name: t.String(),
  email: t.String(),
  createdAt: t.Date(),
});

This is:

  • ❌ Repetitive and error-prone
  • ❌ Hard to maintain (changes need to be synced)
  • ❌ Time-consuming

schema-gen automatically generates validation schemas from your TypeScript classes, keeping them in sync with a single command.

Features

  • 🚀 Generate schemas from TypeScript classes
  • 📦 Multiple schema libraries: Elysia, TypeBox, and Zod
  • 📝 Separate file generation (inline mode coming soon)
  • ⚙️ Flexible configuration via schema-gen.config.json
  • 🎯 Optimized for Bun, compatible with Node.js
  • 🔧 CLI flags override config for one-off cases

Installation

Choose your preferred installation method:

Homebrew (macOS/Linux)

brew tap Naviary-Sanctuary/schema-gen
brew install schema-gen

Bun (Recommended)

bun install -g @naviary-sanctuary/schema-gen

Node.js / npm

This package supports Node.js >= 18.0.0.

npm install -g @naviary-sanctuary/schema-gen

Quick Install Script

curl -fsSL https://raw.githubusercontent.com/Naviary-Sanctuary/schema-gen/main/install.sh | bash

Manual Installation

Download the latest binary from GitHub Releases:

# macOS (ARM64)
curl -L https://github.com/Naviary-Sanctuary/schema-gen/releases/latest/download/schema-gen-macos-arm64 -o schema-gen
chmod +x schema-gen
sudo mv schema-gen /usr/local/bin/

# Linux (x64)
curl -L https://github.com/Naviary-Sanctuary/schema-gen/releases/latest/download/schema-gen-linux-x64 -o schema-gen
chmod +x schema-gen
sudo mv schema-gen /usr/local/bin/

Quick Start

1. Initialize Configuration

schema-gen init

This creates a schema-gen.config.json file:

{
  "mappings": [
    {
      "include": ["src/**/*.ts"],
      "output": {
        "pattern": "schemas/{filename}.schema.ts"
      }
    }
  ],
  "generator": "elysia",
  "exclude": ["**/*.test.ts", "**/*.spec.ts"]
}

2. Create Your Classes

// src/models/user.ts
export class User {
  id: string;
  name: string;
  email: string;
  age?: number;
  tags: string[];
  createdAt: Date;
}

3. Generate Schemas

schema-gen generate

4. Result

// schemas/user.schema.ts
import { t } from 'elysia';

export const userSchema = t.Object({
  id: t.String(),
  name: t.String(),
  email: t.String(),
  age: t.Optional(t.Number()),
  tags: t.Array(t.String()),
  createdAt: t.Date(),
});

CLI Commands

init

Create a default configuration file:

schema-gen init

generate

Generate schemas from your classes:

schema-gen generate

# With custom config path
schema-gen generate -c custom-config.json

# For specific file only (ignores "include" patterns)
schema-gen generate --target src/models/user.ts

Configuration

Basic Configuration

{
  "mappings": [
    {
      "include": ["src/**/*.ts"],
      "output": {
        "pattern": "schemas/{filename}.schema.ts"
      }
    }
  ],
  "generator": "elysia",
  "exclude": ["**/*.test.ts", "**/*.spec.ts"]
}

Configuration Options

| Option | Type | Required | Description | | ----------- | ------------------------ | -------- | ----------------------------------------------------------- | | mappings | MappingRule[] | ✓ | Array of mapping rules defining input/output patterns | | generator | "elysia" \| "typebox" \| "zod" | ✓ | Schema generator to use | | exclude | string[] | ✗ | Global exclude patterns | | overwrite | boolean | ✗ | Whether to overwrite existing files (default: false) | | mode | "separate" \| "inline" | ✗ | Generation mode (default: "separate", inline coming soon) |

Mapping Rule

Each mapping rule defines which files to process and where to output schemas:

{
  "include": string[];  // Glob patterns for files to process
  "output": {
    "pattern": string;  // Output path pattern with variables
  },
  "variables": {        // [Optional] Custom variables
    [key: string]: string | { regex: string };
  }
}

Output Pattern Variables

Use these variables in your output patterns:

  • {filename}: Filename without extension (e.g., user from user.ts)
  • {dirname}: Directory path (e.g., src/models from src/models/user.ts)
  • {extension}: File extension (e.g., .ts)

Custom Variables

You can define custom variables for each mapping rule. These can be static strings or dynamic values extracted from the source file path using regular expressions.

Static Variables

{
  "include": ["src/**/*.ts"],
  "output": { "pattern": "generated/{version}/{filename}.ts" },
  "variables": {
    "version": "v1"
  }
}

Dynamic Extraction (Regex)

Extract parts of the source path using the first capturing group of a regular expression:

{
  "include": ["src/modules/*/domain/*.ts"],
  "output": { "pattern": "generated/{module}/{filename}.schema.ts" },
  "variables": {
    "module": { "regex": "src/modules/([^/]+)/" }
  }
}

If the source file is src/modules/user/domain/model.ts, the {module} variable will be user.

[!TIP] Custom variables can also be used to override built-in variables like {filename} or {dirname} if you define them with the same name.

Advanced Configuration Examples

Multiple Mappings

Process different source directories to different outputs:

{
  "mappings": [
    {
      "include": ["src/models/**/*.ts"],
      "output": {
        "pattern": "src/route/{filename}/schema.ts"
      }
    },
    {
      "include": ["src/dto/**/*.ts"],
      "output": {
        "pattern": "src/api/schemas/{filename}.schema.ts"
      }
    }
  ],
  "generator": "elysia"
}

Result:

src/models/user.ts       → src/route/user/schema.ts
src/dto/product.dto.ts   → src/api/schemas/product.dto.schema.ts

Preserve Directory Structure

Keep the original directory structure in output:

{
  "mappings": [
    {
      "include": ["src/**/*.ts"],
      "output": {
        "pattern": "{dirname}/schemas/{filename}.schema.ts"
      }
    }
  ],
  "generator": "typebox"
}

Result:

src/models/user.ts              → src/models/schemas/user.schema.ts
src/models/domain/product.ts    → src/models/domain/schemas/product.schema.ts

Negative Patterns

Exclude specific patterns from processing:

{
  "mappings": [
    {
      "include": ["src/**/*.ts", "!src/draft/**", "!src/internal/**"],
      "output": {
        "pattern": "schemas/{filename}.schema.ts"
      }
    }
  ],
  "generator": "elysia",
  "exclude": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"]
}

Supported Types

schema-gen supports a wide range of TypeScript types:

Primitives

  • string, number, boolean, Date
  • null, undefined, any

Arrays

tags: string[]           // → t.Array(t.String())
matrix: number[][]       // → t.Array(t.Array(t.Number()))

Objects

address: {
  street: string;
  city: string;
}
// → t.Object({ street: t.String(), city: t.String() })

Unions & Literals

status: 'active' | 'inactive'; // → t.UnionEnum(['active', 'inactive'])
priority: 1 | 2 | 3; // → t.UnionEnum([1, 2, 3])
value: string | number; // → t.Union([t.String(), t.Number()])

Optional Properties

age?: number             // → t.Optional(t.Number())

Schema Generators

Elysia

Uses Elysia's built-in t utility:

import { t } from 'elysia';

export const userSchema = t.Object({
  id: t.String(),
  name: t.String(),
});

TypeBox

Uses standalone TypeBox library:

import { Type as t } from '@sinclair/typebox';

export const userSchema = t.Object({
  id: t.String(),
  name: t.String(),
});

Development

# Install dependencies
bun install

# Run in development
bun run dev

# Build
bun run build

# Run tests
bun test

# Type checking
bun run typecheck

# Linting
bun run lint

# Formatting
bun run format

Contributing

This project follows the Contributor Covenant Code of Conduct.

See CONTRIBUTING.md for contribution guidelines.

License

MIT