jiti
A zero-dependency runtime that transpiles TypeScript and ESM on the fly so Node.js can require() or import them directly.
Repository Health
Technical Analysis
jiti is a runtime for Node.js that gives seamless TypeScript and ESM support without a separate build step. It intercepts require() and import() calls, detects when a file needs transforming (TypeScript, JSX, or mismatched CJS/ESM syntax), transpiles it with a lazily-loaded Babel pipeline, caches the result to disk, and hands back a fully interoperable module — smart syntax detection means untouched JavaScript files pass straight through with no added cost.
It ships as a genuinely zero-dependency package: every dependency it needs at runtime, including Babel itself, is pre-bundled into the published lib/ output, keeping install size small and avoiding version drift in consuming projects. It is used as an internal loader by a large slice of the JavaScript ecosystem — Nuxt, Tailwind CSS, ESLint, Docusaurus, Histoire, Nitro, and dozens of other tools depend on jiti to load user config files and scripts written in TypeScript — and it is also usable standalone via npx jiti ./file.ts or as a global ESM loader through node --import jiti/register.
What You Get
- Async
import()and syncrequire()replacements -jiti.import()and the callablejiti()instance load TypeScript/ESM/CJS files interchangeably, matching Node’s native APIs. - Smart syntax detection - files that don’t need transforming (plain JS) are passed straight through, avoiding unnecessary Babel overhead on hot paths.
- Filesystem transpile cache - transformed output is written to
node_modules/.cache/jiti(or a temp dir) with etag-based invalidation, so repeated runs skip re-transpiling unchanged files. - Global ESM loader registration -
import "jiti/register"ornode --import jiti/registerhooks into Node’s module loader so the whole process gains TS/ESM support. - CLI runner -
npx jiti ./script.tsexecutes a TypeScript file directly with no project setup. - Configurable resolution - custom alias maps,
tsconfig.jsonpathsresolution, and control over whichnode_modulespackages are transformed vs. left native.
Common Use Cases
- Loading TypeScript config files at runtime - tools like Nuxt, Tailwind, and ESLint use jiti internally to
require()a user’snuxt.config.tsortailwind.config.tswithout a pre-build. - Running TypeScript scripts without a build step -
npx jiti ./script.tsfor one-off scripts, codemods, or CI tasks. - Building CLI tools that accept user-authored TS plugins - a CLI can
jiti.import()a user’s.tsplugin file and get back a normal module. - Bridging CJS and ESM in mixed codebases - jiti’s
interopDefaultproxy smooths overdefaultexport mismatches between require() and import() semantics. - Global process-wide TS/ESM support - registering
jiti/registeras a Node loader so an entire process canimport/requireTypeScript without per-call wrapping.
Under The Hood
Architecture
The package is organized as a small set of single-purpose modules under src/ (roughly 1,300 lines total, per the project’s own AGENTS.md): jiti.ts is the createJiti() factory that wires shared context (options, aliases, native-require handles) and returns the callable jiti instance; require.ts implements the synchronous require-replacement path, branching on protocol prefixes (node:, file:, data:), builtin modules, virtual modules, and an experimental Bun “try-native-first” fast path before falling through to resolution and evaluation; resolve.ts handles module resolution with alias and tsconfig-paths support; eval.ts evaluates transformed source for both sync and async contexts; transform.ts and babel.ts orchestrate a lazily-loaded Babel pipeline (only pulled in when a file actually needs transforming); and cache.ts manages the etag-keyed filesystem transpile cache. The design deliberately keeps a shared Context object threaded through every function rather than using global state, which is what lets a single process host multiple independently-configured jiti instances.
Tech Stack
Written in TypeScript, built with rspack (primary) or rolldown as an alternative bundler, and published as dual ESM/CJS output (lib/jiti.mjs / lib/jiti.cjs) plus a CLI entry (lib/jiti-cli.mjs). The published package has zero runtime dependencies — everything it needs, including a full Babel toolchain (@babel/core, @babel/plugin-transform-typescript, @babel/plugin-transform-react-jsx, decorator and explicit-resource-management plugins, etc.), plus small utilities like mlly, pathe, get-tsconfig, and yoctocolors, is bundled into the lib/ output at build time rather than left as installable dependencies. Tests run under Vitest with coverage, plus separate native-mode suites for Bun, Deno, and Node’s own --experimental-strip-types.
Code Quality
The project has an extensive test suite: dozens of fixture directories under test/fixtures (TypeScript, JSX, ESM, CJS interop, tsconfig-paths, import maps, top-level-await, explicit-resource-management, and more) drive snapshot-style fixture tests, alongside dedicated suites for the CLI, the global register hook, virtual modules, and native-runtime parity across Bun/Deno/Node. Error handling favors explicit checks and descriptive thrown errors (e.g. rejecting data: URLs in sync context) over silent fallbacks. CI runs lint (ESLint + Prettier), a type-check pass (tsgo --noEmit), and the full multi-runtime test matrix on every change, and the repo has both AGENTS.md and CLAUDE.md files documenting its own architecture for maintainers.
What Makes It Unique
jiti’s niche is being the de facto shared implementation for “let this tool load a TypeScript config/plugin file without a build step” — rather than every framework reinventing its own ad-hoc TS-loading shim, a large share of the JavaScript tooling ecosystem (Nuxt, Tailwind, ESLint, Docusaurus, Nitro, Histoire, and others) depends on jiti directly for this. Its smart syntax detection (skipping transformation for files that are already valid JS) and its filesystem cache give it a performance profile suited to being invoked on every process start, which is a harder constraint than a one-time build-time transpiler faces.
Used by 21 apps in this directory
OpenClaw
AI Agents · AI Assistants
An open-source AI assistant that runs on your own hardware and meets you in Discord, Slack, WhatsApp, iMessage, Telegram, and 20+ other channels, with native apps for every major platform.
OpenPanel
Analytics
Open-source Mixpanel alternative with session replay, MCP integration, and privacy-first product analytics you fully control.
Openship
Devops · Hosting Control Panel
Openship is an open-source, self-hostable deployment platform that points at a repo and builds, ships, routes, and TLS-terminates the app — driven from a desktop app, web dashboard, or CLI.
Penpot
Design Tools
Open-source design platform with GPU-accelerated canvas, native design tokens, and MCP-powered AI workflows for teams that ship fast.
Pi
AI Agents
An open-source, self-extensible agent harness and coding agent CLI — a modular runtime (agent core, unified multi-provider LLM API, TUI) with no built-in permission system by default, documented containerization patterns for sandboxing instead.
Prime Agent
AI Agents · AI Code Assistants · Developer Tools
An open-source coding and research agent built around a Recursive Language Model that treats context as variables and a persistent Python REPL as its only tool.
Probo
Automation · Security
Open-source GRC platform for engineering and security teams.
Rybbit
Analytics
Open-source, privacy-friendly web and product analytics with cookieless tracking, session replays, funnels, and real-time dashboards — a self-hostable alternative to Google Analytics.
SplitPro
Invoicing Finance
Self-hosted, open source expense splitting with multi-currency, recurring bills, and bank imports — a complete Splitwise replacement you control.