jit 1.0 compiled validators, queries and codecs are out. Star it on GitHub →

jit

The compiled data engine

Compile intent.
Run specialized code.

jit is a schema-first data engine for TypeScript. Describe a shape once and it compiles specialized JavaScript for every operation — validation, equality, cloning, diffing, queries, serialization and more — at runtime or ahead of time.

Get startedStar on GitHubpnpm add @jit-compiler/jit
TypeScript-firstNode 22+Browsers & edge via AOT
user.schema.ts — jit compile
schema
import { JIT } from "@jit-compiler/jit/runtime";

const User = JIT.object({
  id: JIT.number().int().positive(),
  name: JIT.string().min(2),
  email: JIT.string().email(),
  role: JIT.union(JIT.literal("admin"), JIT.literal("user")),
  tags: JIT.array(JIT.string()).max(8),
});

type User = JIT.Typeof<typeof User>;
Users.is.sourcegenerated
// Users.is — generated source (excerpt)
function is(value) {
  let v1 = value;
  if (v1 === null || typeof v1 !== "object" || Array.isArray(v1)) {
    return false;
  }
  let v3 = v1.id;
  if (typeof v3 !== "number") {
    return false;
  }
  if (!Number.isInteger(v3)) {
    return false;
  }
  if (v3 <= 0) {
    return false;
  }
  let v5 = v1.name;
  if (typeof v5 !== "string") {
    return false;
  }
  // …email, role, tags: same straight-line checks
  return true;
}
compiled on first use via globalThis.Function · cached per schema · AOT emits the same code as plain modules
compiled · ~57 ns per is() on Node 22 · cached per schema
15.9x
faster is() than Zod 4
valid object · 56.99 ns vs 903.69 ns
4.4x
faster issue collection than typia
100k users, invalid tail · 6.37 ms vs 27.76 ms
120x
faster immutable update than immer
deep patch · 18.41 ns vs 2.22 µs
8.64x
faster 1M-row load+query, 74% less heap
binary rowsets vs Zod parse + native filter

mitata · Node 22.17.1 · AMD Ryzen 7 5800H · captured 2026-07-11 · reproduce with pnpm bench:*

Why specialization

Interpreting a schema on every call is the tax you never audited

Generic libraries walk the schema tree, branch on types and allocate intermediates for each value they touch. jit walks the schema once — at compile time — and emits the straight-line code a performance engineer would write by hand.

✗ dispatch per call✗ allocates issues
generic path — interpreted per call
// generic library — every call, every field:
function check(schema, value) {
  for (const key of Object.keys(schema.shape)) {
    const rule = schema.shape[key];
    switch (rule.type) {           // dispatch per type
      case "string": /* … */ break;
      case "number": /* … */ break;
      // …walk nested schemas, allocate
      // issue objects, repeat next call
    }
  }
}

Dynamic dispatch, generic loops and issue allocation on the hot path, repeated for every value.

✓ straight-line✓ zero allocation
jit path — specializedgenerated
// jit — compiled once for this exact shape:
function is(value) {
  let v3 = value.id;
  if (typeof v3 !== "number") return false;
  if (!Number.isInteger(v3)) return false;
  if (v3 <= 0) return false;
  let v5 = value.name;
  if (typeof v5 !== "string") return false;
  if (v5.length < 2) return false;
  // static keys, cheapest checks first,
  // early returns, zero allocation
  return true;
}

Static property access, checks ordered cheapest-first (typeof → null → numeric → length → regex), classic indexed loops, no closures.

Schema → IR → generated code

Every operation gets its own compiled function

The output below is the real generated source for each operation — captured from the compiler, not a mockup. Pick an operation and read what actually runs.

  1. 01

    Schema

    zod-like builders describe the shape once. Types are inferred, checks are declarative, runtime values stay out of the source.

  2. 02

    Normalized IR

    The schema AST is normalized into an operation-specific IR: static keys resolved, checks ordered cheapest-first, loops specialized, constants hoisted as external bindings.

  3. 03

    Generated function

    One monomorphic function per operation — compiled at runtime via globalThis.Function and cached, or emitted ahead of time as plain modules.

you write
const isUser = JIT.validate(User).is().compile();

isUser(value); // (value: unknown) => value is User
isUser.source; // the generated function below
jit generatesgenerated
function is(value) {
  let v1 = value;
  if (v1 === null || typeof v1 !== "object" || Array.isArray(v1)) {
    return false;
  }
  let v3 = v1.id;
  if (typeof v3 !== "number") {
    return false;
  }
  if (!Number.isInteger(v3)) {
    return false;
  }
  if (v3 <= 0) {
    return false;
  }
  let v5 = v1.name;
  if (typeof v5 !== "string") {
    return false;
  }
  if (v5.length < 2) {
    return false;
  }
  let v7 = v1.email;
  if (typeof v7 !== "string") {
    return false;
  }
  if (!__v0.test(v7)) {
    return false;
  }
  let v9 = v1.role;
  if (!((v9 === "admin") || (v9 === "user"))) {
    return false;
  }
  let v11 = v1.tags;
  if (!Array.isArray(v11)) {
    return false;
  }
  if (v11.length > 8) {
    return false;
  }
  for (let i13 = 0; i13 < v11.length; i13++) {
    let v14 = v11[i13];
    if (typeof v14 !== "string") {
      return false;
    }
  }
  return true;
}

» run it

isUser({ id: 1, name: "Ada", email: "ada@lovelace.dev", role: "admin", tags: ["compiler"] })  →  true
isUser({ id: -1, name: "A", email: "nope", role: "root", tags: [1] })  →  false

__q0 / __v0 are external bindings — runtime values are never interpolated into generated source.

Runtime JIT vs AOT

Two execution modes, same generated code

Compile lazily at runtime when schemas are dynamic, or generate plain modules at build time when the environment is locked down. The emitted functions are identical.

Runtime cartridge

JIT
runtime.ts
import { JIT } from "@jit-compiler/jit/runtime";

// compiles on first use, cached per schema
const isUser = JIT.validate(User).is().compile();

isUser(input);
isUser.source;    // inspect the generated code
isUser.explain(); // { operation, hash, source, cache }
  • · compiles once per schema via globalThis.Function, then reuses the cached function
  • · two cache tiers: applied functions and rebindable source templates
  • · ideal for dynamic schemas and long-lived processes
  • · requires an environment that allows runtime code generation

Build cartridge

AOT
jit generate
# Prisma-style workflow
pnpm jit init      # writes jit.config.ts
pnpm jit generate  # emits .mjs + .cjs + .d.ts

# generated modules have zero imports —
# the engine never ships to production
import { User } from "@jit/generated";
User.is(input);
  • · pure .mjs + .cjs + .d.ts output with zero imports — error class and helpers inlined
  • · no compile cost at runtime, predictable deploys
  • · works under strict CSP, edge runtimes and locked-down environments
  • · the final bundle keeps only the generated functions you import

Operations

One schema. Every operation compiled.

Each operation is its own emitter following the same codegen rules — you only pay for what you compile.

  • .validateis / parse / safeParse with structured issues
  • .equalschema-aware deep equality with strategies
  • .clonestatic-literal deep clone
  • .diffstructural diff entries
  • .hashinline FNV-1a — no JSON.stringify
  • .updateimmutable surgical updates, no Proxy
  • .queryfused single-loop pipelines, no intermediates
  • .mapperwhitelist-by-construction DTO mapping
  • .transformcompiled field selection and operators
  • .maskPII-safe copies for structured logs
  • .sanitizeXSS-stripped copies, fused into parse
  • .stringifycompiled JSON with static keys
  • .codecversioned binary wire format v2
  • .streamprogressive validation across chunks
  • .rowsetbinary rows for massive flat batches

Optimizer pipeline

From schema to straight-line code

Every emitter follows the same non-negotiable codegen rules; equal and query additionally run dedicated IR optimizer passes before emission.

  1. schema DSL
  2. schema AST
  3. IR
  4. optimizer passes
  5. codegen
  6. Function / AOT module

External bindings only

Runtime values (regexes, refinement callbacks, query arguments) travel as __q0/__v0 bindings — never interpolated into generated source.

Static shapes, static keys

No for...in or Object.keys over known shapes. Property access is compiled per field, in declaration order.

Cheapest checks first

typeof → null → numeric → length → regex. The generated order is part of the contract, verified by byte-exact golden tests.

Dedicated optimizer passes

equal and query run their own IR passes — inline-vars, optimize-cost, reorder-compares — with cost tables tuned per operation.

Benchmarks

Measured against the fastest in the field

Zod 4, typia's generated validators, TypeBox's compiled checkers, fast-json-stringify — the numbers below are the results published in the repository README, with the exact command to reproduce each suite.

is() — valid objectlower is better · pnpm bench:validate

Boolean guard over a realistic user object.

is() — 100k valid userslower is better · pnpm bench:load

Same benchmark at 100k rows — jit stays allocation-free.

safeParse — 100k users, invalid taillower is better · pnpm bench:load

Issue collection at the end of a 100k batch.

equal — array with 100k itemslower is better · pnpm bench:equal

Schema-aware deep equality over a large collection.

update — deep immutable patchlower is better · pnpm bench:update

Surgical immutable update of a nested object (no Proxy).

JSON stringify — medium userlower is better · pnpm bench:serialize

Compiled serializer with static keys and escape fast path.

adaptive load+query — 1M dynamic rowslower is better · pnpm bench:binary

Unknown input → validated rowset → byte-offset query.

Benchmark results table

Benchmark results with environment Node 22.17.1, AMD Ryzen 7 5800H
SuiteImplementationAvg time
is() — valid objectjit (AOT)56.99 ns
jit (runtime)57.56 ns
Zod 4903.69 ns
is() — 100k valid usersjit7.01 ms
typia (generated)7.17 ms
TypeBox (compiled)7.22 ms
Zod 4114.15 ms
safeParse — 100k users, invalid tailjit6.37 ms
typia (generated)27.76 ms
Zod 4111.38 ms
TypeBox (compiled)300.24 ms
equal — array with 100k itemsjit734.37 µs
fast-deep-equal9.58 ms
update — deep immutable patchjit18.41 ns
immer2.22 µs
JSON stringify — medium userjit207.49 ns
fast-json-stringify266.52 ns
adaptive load+query — 1M dynamic rowsjit rowset (adaptive)52.67 ms
Zod 4 parse + native filter454.89 ms
mitata · Node 22.17.1 · linux-x64 · AMD Ryzen 7 5800H · captured 2026-07-11Zod 4.4.3 · TypeBox 0.34 · typia 12 · fast-json-stringify 7

Heap measurements, methodology and every other suite live on the benchmarks pages; run pnpm bench:all for your own hardware.

See all suites →

Developer experience

Compiled does not mean opaque

Every compiled function carries its own source, hash and cache report — and the CLI explains what would be generated before you ship it.

Types inferred end-to-end

Schemas carry their TypeScript type — JIT.Typeof on builders, typed params on queries, typed DTOs on mappers. A Standard Schema v1 facade covers framework interop.

type User = JIT.Typeof<typeof User>;
//   ^? { id: number; name: string; email: string;
//        role: "admin" | "user"; tags: string[] }

Inspectable output

fn.source returns the generated code, fn.hash a deterministic source hash and fn.explain() the operation, cache tier and source in one report — the same output this page embeds.

CLI workflow

jit init scaffolds config, jit doctor checks the setup, jit explain previews generated code and jit generate writes the AOT modules.

Two-tier compile cache

Tier A caches applied functions for schema-derived bindings; tier B caches source templates and rebinds user values per compile — repeated schemas never pay codegen twice. An MCP server (jit-mcp) exposes the same tooling to agents.

Runtime compatibility

Honest about where each mode runs

Runtime JIT needs an environment that allows code generation. AOT removes that requirement entirely — the generated modules are just JavaScript files.

Node.js 22+

primary

The reference runtime — the full test suite, benchmarks and CI run here. Both JIT and AOT modes are supported.

Browsers

aot-first

Generated functions are plain JavaScript. Runtime compilation needs new Function — blocked by strict CSP — so prefer AOT output for browser bundles.

Deno & JSR

npm + JSR

Published as @jit-compiler/jit on npm and @jit/compiler on JSR. Dual ESM + CJS builds with subpath exports for runtime, CLI and MCP.

Edge & serverless

aot

AOT modules have zero imports and zero codegen at runtime — predictable cold starts in restricted environments.

Distributed via npm and JSR, MIT licensed.

Ship the code you meant to write

One schema in, specialized functions out. Read the docs, run the benchmarks on your own machine, and star the project if the generated code speaks for itself.

pnpm add @jit-compiler/jit