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.
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;}
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.
01
Schema
zod-like builders describe the shape once. Types are inferred, checks are declarative, runtime values stay out of the source.
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.
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 UserisUser.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;}
const toJSON = JIT.json(User).stringify().compile();toJSON(user); // static keys baked in, escape fast path
jit generatesgenerated
// excerpt — str() escape fast-path helper omittedfunction stringify(value) { let s = ""; s += "{"; s += "\"id\":"; s += Number.isFinite(value.id) ? "" + value.id : "null"; s += ",\"name\":"; s += str(value.name); s += ",\"email\":"; s += str(value.email); s += ",\"role\":"; s += JSON.stringify(value.role) ?? "null"; s += ",\"tags\":"; const v1 = value.tags; s += "["; for (let i2 = 0; i2 < v1.length; i2++) { if (i2 !== 0) s += ","; const e3 = v1[i2]; s += str(e3); } s += "]"; s += "}"; return s;}
__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 schemaconst isUser = JIT.validate(User).is().compile();isUser(input);isUser.source; // inspect the generated codeisUser.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 workflowpnpm jit init # writes jit.config.tspnpm jit generate # emits .mjs + .cjs + .d.ts# generated modules have zero imports —# the engine never ships to productionimport { 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.
schema DSL→
schema AST→
IR→
optimizer passes→
codegen→
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.
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.
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.