jit
AOT

CLI and configuration

Initialize, inspect, generate and clean an AOT project.

pnpm jit init
pnpm jit doctor
pnpm jit list
pnpm jit explain
pnpm jit inspect User --stage source
pnpm jit generate
pnpm jit clean

init writes a typed jit.config.ts in the project root and a starter *.jit.ts declaration. Review those two files, export only the compiled operations the application uses, then run generate.

Complete local setup

jit.config.ts
import { AOT } from "@jit-compiler/jit";

export default AOT.defineConfig({
  entries: ["src/aot/**/*.jit.ts"],
  patterns: ["**/*.jit.ts"],
  output: {
    directory: "src/generated/jit",
    clean: true,
  },
  emit: {
    subpathModules: true,
    manifest: true,
    plans: true,
  },
  types: {
    package: "@jit-compiler/jit",
  },
});
src/aot/users.jit.ts
import { JIT } from "@jit-compiler/jit/define";

const UserSchema = JIT.object({
  id: JIT.number().int32(),
  name: JIT.string().min(2),
  role: JIT.union(JIT.literal("admin"), JIT.literal("member")),
});
const UsersSchema = JIT.array(UserSchema);
const selected = JIT.validator(UserSchema).get("is", "parse");

// Grouped import: User.is(), User.parse().
export const User = JIT.compile(UserSchema, {
  is: selected.is,
  parse: selected.parse,
});

// Standalone exports keep these declaration names exactly.
export const findAdmins = JIT.query(UsersSchema)
  .filter((q) => q.eq("role", "admin"))
  .compile();
export const watchUsers = JIT.watch(UsersSchema, { key: "id" });
pnpm jit doctor
pnpm jit explain
pnpm jit generate
src/service.ts
import {
  User,
  findAdmins,
  watchUsers,
} from "./generated/jit/index.js";

if (User.is(input)) {
  const admins = findAdmins(users);
  const changes = watchUsers(previousUsers, users);
}

The generated JavaScript contains the specialized loops and checks but no schema builders or runtime compiler import. Matching declarations preserve the schema-derived types at the import site.

Output layout is automatic. A project-local directory emits index.js and index.d.ts for normal relative imports. A directory below node_modules emits a namespaced dual ESM/CommonJS package and exports map.

If no explicit compiled exports are found, generation prints a diagnostic and writes nothing. There is no raw-schema fallback.

Configuration reference

OptionDefaultPurpose
entriesproject-root scandeclaration files, directories or globs to load
patterns['**/*.jit.ts']patterns applied while scanning a directory
output.directorygenerated/jitlocal directory or generated package location
output.packageNameinferrednamespace override for output below node_modules
output.cleantrueremove known artifacts from the previous generation
emit.subpathModulesfalseemit one import entry per declaration file
emit.manifestfalserecord modules, imports, exports and generated files
emit.plansfalsewrite deterministic plans for review and CI
types.package@jit-compiler/jitsource of JIT.Typeof/strict helpers in declarations

Discovery

entries accepts files, directories and globs. Directory scans use patterns (default **/*.jit.ts) and skip node_modules, dot directories and generated output. Omit entries to scan from the project root.

import { AOT } from "@jit-compiler/jit";

export default AOT.defineConfig({
  entries: ["src/schemas/**/*.ts", "jit"],
  patterns: ["**/*.jit.ts", "**/*.schema.ts"],
});

Output modes

Generate into node_modules/@jit/generated when consumers should import @jit/generated. Generate into src/generated/jit for ./generated/jit/index.js. No # import alias or nested-package toggle is required.

export default AOT.defineConfig({
  entries: ["src/**/*.jit.ts"],
  output: { directory: "src/generated/jit", clean: true },
  emit: { subpathModules: true, manifest: true, plans: true },
  types: { package: "@jit-compiler/jit" },
});

clean: true removes only known generated files before a new generation. It does not recursively delete arbitrary user files.

Generated package output

For package-style imports, place output below node_modules:

jit.config.ts
import { AOT } from "@jit-compiler/jit";

export default AOT.defineConfig({
  entries: ["src/aot/**/*.jit.ts"],
  output: {
    directory: "node_modules/@jit/generated",
    packageName: "@jit/generated",
    clean: true,
  },
  emit: { subpathModules: true, manifest: true },
});
import { User } from "@jit/generated";
import { watchUsers } from "@jit/generated/users";

This layout writes index.mjs, index.cjs, matching declarations and a generated package.json exports map. Run generation after dependency installs, because package managers own and may replace node_modules.

Diagnostics workflow

  1. doctor: resolved config, patterns, output and discovered files.
  2. list: buildable grouped and standalone exports.
  3. explain: why each declaration can/cannot build.
  4. inspect --stage plan: normalized operation descriptor.
  5. inspect --stage source: exact generated JS.
  6. inspect --stage declaration: public generated types.

Use this sequence in CI before generation when config drift should fail early.

explain and inspect are especially useful for callback-bound operations. The CLI reports a serialization boundary instead of silently embedding an arbitrary runtime closure into generated code.

CI

Run generate in a clean checkout and fail when generated files differ. This proves declarations are current and prevents local stale artifacts from hiding missing exports.

pnpm jit doctor
pnpm jit generate
git diff --exit-code -- src/generated/jit

When generated files are intentionally excluded from source control, run pnpm jit generate before the application build and cache the output directory as a build artifact instead.

On this page