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

@zipbul/baker

v2.2.0

Published

Fastest decorator-based DTO validation for TypeScript. AOT code generation, 42ns per validation, 163x faster than class-validator. Zero reflect-metadata.

Readme

@zipbul/baker

The fastest decorator-based DTO validation library for TypeScript. Generates optimized validation and serialization code on first seal, then reuses the sealed executors on every call.

bun add @zipbul/baker

Zero reflect-metadata. Sealed codegen. 1,975 tests. 99%+ line coverage.

Quick Start

import { deserialize, isBakerError, Field } from '@zipbul/baker';
import { isString, isNumber, isEmail, min, minLength } from '@zipbul/baker/rules';

class UserDto {
  @Field(isString, minLength(2)) name!: string;
  @Field(isNumber(), min(0)) age!: number;
  @Field(isString, isEmail()) email!: string;
}

const result = await deserialize(UserDto, {
  name: 'Alice', age: 30, email: '[email protected]',
});

if (isBakerError(result)) {
  console.log(result.errors); // [{ path: 'email', code: 'isEmail' }]
} else {
  console.log(result.name);   // 'Alice' — typed as UserDto
}

Why Baker?

Baker generates optimized JavaScript functions once on first seal, then executes them on every call.

| Feature | baker | class-validator | Zod | |---|---|---|---| | Valid path (5 fields) | fast sealed path | slower | slower | | Invalid path (5 fields) | fast sealed path | slower | slower | | Approach | AOT code generation | Runtime interpretation | Schema method chain | | Decorators | @Field (unified) | 30+ individual | N/A | | reflect-metadata | Not needed | Required | N/A | | Sync DTO return | Direct value | Promise | Direct value |

Performance

Benchmarked against multiple libraries on simple, nested, array, and error-collection scenarios. Exact numbers vary by machine and runtime.

See bench/ for the current benchmark suite and exact scenarios.

API

deserialize<T>(Class, input, options?)

Returns T | BakerErrors for sync DTOs, Promise<T | BakerErrors> for async DTOs. Never throws on validation failure.

serialize<T>(instance, options?)

Returns Record<string, unknown> for sync DTOs, Promise<Record<string, unknown>> for async DTOs. No validation.

validate(Class, input, options?) / validate(input, ...rules)

DTO-level or ad-hoc single-value validation. Returns true | BakerErrors for sync paths, Promise<true | BakerErrors> for async paths.

isBakerError(value)

Type guard. Narrows result to BakerErrors containing { path, code, message?, context? }[].

configure(config)

Global configuration. Call before first deserialize/serialize/validate. Calling it after auto-seal throws SealError.

configure({
  autoConvert: true,        // coerce "123" → 123
  allowClassDefaults: true, // use class field initializers for missing keys
  stopAtFirstError: true,   // return on first validation failure
  forbidUnknown: true,      // reject undeclared fields
});

createRule(name, validate)

Custom validation rule.

const isEven = createRule({
  name: 'isEven',
  validate: (v) => typeof v === 'number' && v % 2 === 0,
  requiresType: 'number',
});

@Field Decorator

One decorator for everything — replaces 30+ individual decorators from class-validator.

@Field(...rules)
@Field(...rules, options)
@Field(options)

Options

| Option | Type | Description | |---|---|---| | type | () => Dto \| [Dto] | Nested DTO. [Dto] for arrays | | discriminator | { property, subTypes } | Polymorphic dispatch | | optional | boolean | Allow undefined | | nullable | boolean | Allow null | | name | string | Bidirectional key mapping | | deserializeName | string | Input key mapping | | serializeName | string | Output key mapping | | exclude | boolean \| 'deserializeOnly' \| 'serializeOnly' | Field exclusion | | groups | string[] | Conditional visibility | | when | (obj) => boolean | Conditional validation | | transform | Transformer \| Transformer[] | Value transformer | | message | string \| (args) => string | Error message override | | context | unknown | Error context | | mapValue | () => Dto | Map value DTO | | setValue | () => Dto | Set element DTO |

Transformers

Bidirectional value transformers with separate deserialize and serialize methods.

import type { Transformer } from '@zipbul/baker';

const centsTransformer: Transformer = {
  deserialize: ({ value }) => typeof value === 'number' ? value * 100 : value,
  serialize: ({ value }) => typeof value === 'number' ? value / 100 : value,
};

Built-in Transformers

import {
  trimTransformer, toLowerCaseTransformer, toUpperCaseTransformer,
  roundTransformer, unixSecondsTransformer, unixMillisTransformer,
  isoStringTransformer, csvTransformer, jsonTransformer,
} from '@zipbul/baker/transformers';

| Transformer | deserialize | serialize | |---|---|---| | trimTransformer | trim string | trim string | | toLowerCaseTransformer | lowercase | lowercase | | toUpperCaseTransformer | uppercase | uppercase | | roundTransformer(n?) | round to n decimals | round to n decimals | | unixSecondsTransformer | unix seconds → Date | Date → unix seconds | | unixMillisTransformer | unix ms → Date | Date → unix ms | | isoStringTransformer | ISO string → Date | Date → ISO string | | csvTransformer(sep?) | "a,b"["a","b"] | ["a","b"]"a,b" | | jsonTransformer | JSON string → object | object → JSON string |

Transform Array Order

Multiple transformers apply as a codec stack:

  • Deserialize: left to right — [A, B, C] applies A, then B, then C
  • Serialize: right to left — [A, B, C] applies C, then B, then A
@Field(isString, { transform: [trimTransformer, toLowerCaseTransformer] })
email!: string;
// deserialize "  HELLO  " → trim → toLowerCase → "hello"
// serialize   "hello"     → toLowerCase → trim → "hello"

Optional Peer Transformers

// bun add luxon
import { luxonTransformer } from '@zipbul/baker/transformers';
const luxon = await luxonTransformer({ zone: 'Asia/Seoul' });

class EventDto {
  @Field({ transform: luxon }) startAt!: DateTime;
}
// bun add moment
import { momentTransformer } from '@zipbul/baker/transformers';
const mt = await momentTransformer({ format: 'YYYY-MM-DD' });

Rules

104 built-in validation rules.

Type Checkers

isString, isInt, isBoolean, isDate, isArray, isObject — constants, no () needed.

isNumber(options?), isEnum(entity) — factories, require ().

Numbers

min(n), max(n), isPositive, isNegative, isDivisibleBy(n)

Strings

minLength(n), maxLength(n), length(min, max), contains(seed), notContains(seed), matches(regex)

Formats

isEmail(), isURL(), isUUID(version?), isIP(version?), isISO8601(), isJSON, isJWT, isCreditCard, isIBAN(), isFQDN(), isMACAddress(), isBase64(), isHexColor, isSemVer, isMongoId, isPhoneNumber(), isStrongPassword(), isULID(), isCUID2()

Arrays

arrayMinSize(n), arrayMaxSize(n), arrayUnique(), arrayNotEmpty, arrayContains(values), arrayOf(...rules)

Common

equals(val), notEquals(val), isIn(values), isNotIn(values), isEmpty, isNotEmpty

Date

minDate(date), maxDate(date)

Locale

isMobilePhone(locale), isPostalCode(locale), isIdentityCard(locale), isPassportNumber(locale)

Nested DTOs

class AddressDto {
  @Field(isString) city!: string;
}

class UserDto {
  @Field({ type: () => AddressDto }) address!: AddressDto;
  @Field({ type: () => [AddressDto] }) addresses!: AddressDto[];
}

Collections

class UserDto {
  @Field({ type: () => Set as any, setValue: () => TagDto }) tags!: Set<TagDto>;
  @Field({ type: () => Map as any, mapValue: () => PriceDto }) prices!: Map<string, PriceDto>;
}

Discriminator

class PetOwner {
  @Field({
    type: () => CatDto,
    discriminator: {
      property: 'kind',
      subTypes: [
        { value: CatDto, name: 'cat' },
        { value: DogDto, name: 'dog' },
      ],
    },
  }) pet!: CatDto | DogDto;
}

Inheritance

class BaseDto {
  @Field(isString) id!: string;
}

class UserDto extends BaseDto {
  @Field(isString) name!: string;
  // inherits 'id' field with isString rule
}

FAQ

When should I use baker instead of class-validator?

When performance matters. baker is 163x faster on valid input and 109x faster on invalid input, while providing the same decorator-based DX. baker also eliminates the reflect-metadata dependency.

How does baker compare to Zod?

Zod uses schema method chains (z.string().email()), baker uses decorators (@Field(isString, isEmail())). baker is 16x faster on valid input because it generates optimized code at definition time instead of interpreting schemas at runtime. Choose Zod if you need schema-first design; choose baker if you need class-based DTOs with maximum performance.

Does baker support async validation?

Yes. If any rule or transformer is async, baker automatically detects it at seal time and generates an async executor. Sync DTOs return values directly without Promise wrapping.

Can I use baker with NestJS?

Yes. baker's @Field decorator works alongside NestJS pipes. Use deserialize() in a custom validation pipe.

How does the AOT code generation work?

On the first call to deserialize/serialize/validate, baker seals all registered DTOs: it analyzes field metadata, generates optimized JavaScript validation functions via new Function(), and caches them. Subsequent calls execute the pre-compiled functions directly.

Exports

import { deserialize, validate, serialize, configure, createRule, Field, arrayOf, isBakerError, SealError } from '@zipbul/baker';
import type { Transformer, TransformParams, BakerError, BakerErrors, FieldOptions, EmittableRule, RuntimeOptions } from '@zipbul/baker';
import { isString, isEmail, isULID, isCUID2, ... } from '@zipbul/baker/rules';
import { trimTransformer, jsonTransformer, ... } from '@zipbul/baker/transformers';

License

MIT