Skip to content

CLI Reference

Terminal window
zntc <file.ts> # → stdout
zntc <file.ts> -o <out.js> # → file
zntc <dir/> --outdir <out/> # recursive directory
zntc - < input.ts # stdin
Terminal window
zntc --bundle <entry.ts> # → stdout
zntc --bundle <entry.ts> -o out.js # → file
zntc --bundle <entry.ts> --splitting --outdir dist # code splitting
zntc --bundle <entry.ts> --preserve-modules --outdir dist # per-module (library)
zntc --bundle <entry.ts> --plugin zntc.config.js # JS plugin
Terminal window
zntc dev [root] # index.html-based dev server
zntc build [root] # HTML rewrite + hashed assets → dist/
zntc preview [outdir] # serve built files only

The default app layout is index.html, public/, src/main.ts(x), and .env*. zntc build uses <script type="module" src> as bundle entries and rewrites CSS url(), HTML asset URLs, and %ENV% tokens, and injects modulepreload links for static split chunks. zntc dev uses the same HTML/env/public prepare step and updates stylesheets for CSS edits without a full page reload.

OptionDescription
--entry-html <file>HTML entry file (default: index.html)
--public-dir <dir|false>public copy directory or disabled
--base <path>HTML/CSS asset URL prefix
--mode <name>env/config mode (dev: development, build: production)
--env-prefix <list>exposed env prefix CSV (default: VITE_,ZNTC_)
--env-dir <dir>directory for .env* files
--spa-fallback[=file]in preview, fall back route-like 404 requests to index.html or the given file
--jsx*JSX runtime (--jsx, --jsx-dev, --jsx-import-source, --jsx-factory, --jsx-fragment). When unset, the app root tsconfig.json jsx / jsxImportSource is used

zntc dev / zntc build resolve the JSX runtime in this order: CLI --jsx* options → app root tsconfig.json (compilerOptions.jsx / jsxImportSource) → default classic (React.createElement). Non-React apps such as preact/solid only need "jsx": "react-jsx", "jsxImportSource": "preact" in tsconfig.json for both dev and build to work.

If the app root contains postcss.config.{js,mjs,cjs,json} or .postcssrc*, ZNTC automatically applies it to CSS. In zntc dev, original CSS files and PostCSS dependency / dir-dependency messages are watched and CSS-only edits are sent as stylesheet HMR updates. Tailwind v4 works via @tailwindcss/postcss. CSS Modules (.module.css) in app mode are transformed into scoped class maps with default exports and valid named exports. .scss / .sass files are compiled to CSS before PostCSS when the optional sass dependency is installed.

This is a separate npx entry point that adds ZNTC scripts and config to an existing React Native CLI project. Expo project creation/initialization is currently out of scope.

Terminal window
npx @zntc/init
npx @zntc/init --help
Usage: zntc-init [react-native] [options]
Overlay ZNTC onto an existing React Native CLI project.
Options:
--root <dir> Project root (default: cwd)
--platform <ios|android> Default platform for the start script (default: ios)
--zntc-version <range> Version range for @zntc packages (default: latest)
--package-manager <pm> Install command hint: bun, npm, pnpm, or yarn
--no-metro-fallback Do not add Metro fallback scripts
--force Overwrite an existing zntc.config.ts
--dry-run Print planned changes without writing files
--help, -h Show this help message
OptionDescription
--root <dir>Project root. Defaults to the current directory
--platform <ios|android>Default RN platform for the start script. Defaults to ios
--zntc-version <range>Version range for @zntc/core and @zntc/react-native
--package-manager <bun|npm|pnpm|yarn>Install command hint printed after initialization
--no-metro-fallbackDo not add Metro fallback scripts
--forceOverwrite an existing zntc.config.ts
--dry-runPrint planned changes without writing files
--help, -hShow help
OptionDescription
-o, --out-file <path>Output file path (the JS wrapper also accepts --outfile as alias)
--outdir <path>Output directory (required for dir input / splitting / preserve-modules)
--outbase=<dir>Base dir for computing output paths
--out-extension:.js=<ext>Change output extension (e.g. .mjs)
--cleanClear outdir before building
OptionDescription
--format=esm|cjs|iife|umd|amdModule format (default: esm)
--platform=browser|node|neutral|react-nativeTarget platform
--rn-platform=ios|androidRN sub-platform (.ios.*/.android.* extensions)
--target=<spec>ES target: es2015esnext or engine versions (chrome80,safari14)
--browserslist=<query>Browserslist query as the ES downlevel target ("defaults", "last 2 versions, not dead" — an alternative to --target)
--runtime-polyfills=auto|usage|entry|offInject core-js runtime API polyfills. auto/usage use graph usage
--runtime-target=<query>core-js polyfill Browserslist target. Repeatable (ios_saf 12)
--core-js=<version>core-js version used by core-js-compat
--global-name=<name>IIFE export name

zntc --bundle --platform=react-native accepts the standard react-native bundle (Metro CLI) flags as a dropin. Commonly used:

OptionDescription
--bundle-output=<path>Bundle output path (same as -o; fallback when -o not given)
--sourcemap-output=<path>Source map output path (implies sourcemap when set)
--source-map-url=<url>Value for //# sourceMappingURL
--assets-dest=<dir>Asset copy destination in production builds (iOS 1x/2x/3x, Android res/)
--bundle-encoding=<utf8|utf16le|ascii>Bundle file encoding (default utf-8)
--reset-cacheInvalidate the cache on startup
--max-workers=<n>Parallel worker count — alias of --jobs
--rn-project-root=<dir>RN preset projectRoot (defaults to cwd; set for monorepo roots)
--watchFolders=<a,b> / --sourceExts=<a,b>Metro camelCase forms — forwarded to the RN preset (distinct from --watch-folder)
--sourcemap-sources-root=<dir> / --sourcemap-use-absolute-path / --no-interactiveMetro compat options
--asset-catalog-dest=<dir> / --unstable-transform-profile=<name> / --transform-option=<k=v> / --resolver-option=<k=v>Accepted but currently ignored (Metro graph-bundler only)

Full table + behavior: React Native guide

OptionDescription
--minifyEnable all three (shortcut)
--minify-whitespaceWhitespace/semicolons/newlines only (debuggable)
--minify-syntaxtrue!0, paren removal, constant folding
--minify-identifiersShorten local identifiers
--keep-namesPreserve function/class .name
--charset=utf8Preserve non-ASCII verbatim (parser only accepts utf8)
--ascii-onlyNon-ASCII → \uXXXX (asymmetric — --charset=ascii is not accepted)
--quotes=double|single|preserveString quote style
--line-limit=<n>Wrap long output lines at safe token boundaries (0 disables wrapping)
OptionDescription
--sourcemapExternal .js.map with sourceMappingURL comment (linked, default)
--sourcemap=linkedExplicit linked mode (#2152) — same as above
--sourcemap=inlineInline data URL
--sourcemap=externalExternal file, no comment
--sourcemap-debug-idsSentry debugId support
--sources-content=falseOmit sourcesContent
--source-root=<path>sourceRoot field
OptionDescription
--define:KEY=VALUEGlobal replace (e.g. process.env.NODE_ENV"production")
--drop=consoleRemove console.* calls
--drop=debuggerRemove debugger statements
--drop-labels=DEV,TESTRemove whole labeled statements for matching labels
--inject:<path>Auto-inject import (shim)
--pure:CALLRegister a pure call pattern (for example --pure:React.createElement)
--ignore-annotationsIgnore tree-shaking annotations such as /* @__PURE__ */ and sideEffects
OptionDescription
--jsx=classic|automatic|automatic-devJSX runtime
--jsx-dev--jsx=automatic-dev shortcut
--jsx-factory=<fn>Classic factory (default: React.createElement)
--jsx-fragment=<fn>Classic Fragment
--jsx-import-source=<pkg>Automatic import source (default: react)
--jsx-in-jsAllow JSX parsing in .js files
--jsx-side-effectsPreserve unused JSX expressions as side-effectful

Per-file comments override that file’s JSX settings (same as esbuild/TypeScript/Babel). Precedence: file pragma > tsconfig / CLI options > defaults. // line comments work too.

  • /** @jsx h */ — classic factory (= --jsx-factory)
  • /** @jsxFrag Fragment */ — classic fragment (= --jsx-fragment)
  • /** @jsxRuntime automatic|classic */ — runtime mode (= --jsx)
  • /** @jsxImportSource preact */ — automatic import source (= --jsx-import-source)

@jsx / @jsxFrag only take effect when the effective runtime is classic (the automatic runtime doesn’t use a factory). E.g. a project on React (jsx: react-jsx) can have one file use preact by adding just /** @jsxImportSource preact */ — that file alone uses preact/jsx-runtime.

OptionDescription
-p, --project <path>, --tsconfig-path <path>tsconfig.json path/directory
--experimental-decoratorsLegacy decorator (__decorateClass)
--emit-decorator-metadataEmit decorator metadata (requires experimentalDecorators, JS-wrapper-only)
--use-define-for-class-fields=false|trueClass field semantics
--verbatim-module-syntaxPreserve TS verbatimModuleSyntax imports/exports
--tsconfig-raw=<json>Inline tsconfig JSON string, compatible with esbuild tsconfigRaw
OptionDescription
--flowFlow type stripping (auto-detected via @flow pragma)
OptionDescription
--bundleEnable bundle mode
--splittingCode splitting (requires --outdir)
--no-splittingDisable splitting from config at the CLI layer
--preserve-modulesPer-module output (library build)
--preserve-modules-root=<dir>Root for output structure
--inline-dynamic-importsAbsorb dynamic-import targets into the entry chunk (Rollup inlineDynamicImports, #2185)
--output-exports=<mode>CJS/UMD entry export shape — auto|named|default|none (Rollup output.exports, #2159)
--entry-names=<pattern>Entry name pattern ([name], [hash])
--chunk-names=<pattern>Chunk name pattern
--asset-names=<pattern>Asset name pattern
--loader:.ext=typeLoader by extension (file|dataurl|base64|text|binary|copy|empty|json|css|js|ts|jsx|tsx)
--metafile / --metafile=<path>Build meta JSON (stdout or file)
--analyzeBundle analysis report (printed to stderr). Pair with --metafile=<path> to also write JSON to disk; upload it at /analyze/
--legal-comments=<mode>License comments: none|inline|eof|linked|external (linked/external currently fall back to eof)
--packages=externalTreat all bare package imports as external
--banner:js=<text>Prepend text (the bare --banner= form is JS-wrapper-only)
--footer:js=<text>Append text (the bare --footer= form is JS-wrapper-only)
--intro=<text>Prepend wrapper-internal bundle text (JS-wrapper-only — native parser does not accept it)
--outro=<text>Append wrapper-internal bundle text (JS-wrapper-only — native parser does not accept it)
--global:FROM=TOMap an IIFE/UMD external specifier to a global variable name
--global-identifier=<name>Reserve a global identifier during scope hoisting (repeatable)
--polyfill=<path>Run-on-startup polyfill module path (repeatable, resolved to absolute path)
--run-before-main=<path>Module to execute right before the entry module (repeatable, resolved to absolute path)
--public-path=<url>Asset URL prefix
--shim-missing-exportsShim missing exports with undefined
OptionDescription
--external <pkg> / --external=<pkg>Exclude from bundle (repeatable)
--alias:FROM=TOImport path alias
--resolve-extensions=<exts>Extension lookup order (e.g. .ios.ts,.ts,.js)
--main-fields=<fields>package.json field order (e.g. react-native,browser,main)
--conditions=<list>Add package exports conditions from a CSV list (for example prod,react-native)
--node-paths=<list>Additional bare-specifier lookup paths from a CSV list
--preserve-symlinksDon’t resolve symlinks
OptionDescription
-w, --watchWatch for file changes (incremental rebuild)
--watch-jsonNDJSON event output (for external HMR integration)
--watch-delay=<ms>Debounce delay
--watch-folder=<dir>Add a directory to watch roots (Metro watchFolders compatible, resolved to absolute path, repeatable)
--watch-include=<glob>Whitelist glob for watchFolders scanning (repeatable)
--watch-exclude=<glob>Exclude glob for watchFolders scanning (repeatable)
--devEnable dev mode (turn on dev-only behavior such as HMR runtime injection)
--serve [dir]Static file server (default: .)
--port <n>Server port
--host [addr]Binding address
--strict-portFail instead of falling through to the next port when the requested port is busy
--certfile <path>HTTPS certificate file (preview/serve)
--keyfile <path>HTTPS private key file (preview/serve)
--openAuto-open browser
--proxy /api=http://host:portAPI proxy

Dev server external interfaces: /sse/events (SSE build events), /reset-cache (Control API), /mcp (Model Context Protocol — for LLM agents like Claude Code).

OptionDescription
--plugin <path>JS/TS plugin or config file
--jobs=<n>Parallel thread count
--config <path>Use an explicit zntc.config.* instead of auto-discovery
--workspace-config <path>Use an explicit zntc.workspace.* instead of auto-discovery
--workspace <name>Select one workspace entry
OptionDescription
--log-level=<level>silent|error|warning|info|debug|verbose
--log-limit=<n>Max diagnostics shown
--profile=<list>Collect profile categories from a CSV list (all, parse, transform, etc.)
--profile-level=<level>Profile detail level: summary|detailed|per-module|per-pass
--profile-format=<format>Profile output: table|tree|json|csv
--tokenize[=false]Print scanner tokens instead of generated code
--tokenize-format=<format>Token output format: text|json
--stop-after=<phase>Debug option to stop after a compiler phase (scan|parse|semantic|transform|codegen)
--test262 <dir>Run the Zig Test262 runner
--allow-overwriteExplicitly permit an output path to overwrite an input file. Blocked by default.
-h, --helpShow help

A subcommand that runs the requested phases N times and prints mean/median/p95/p99/stddev/min/max statistics. Use baseline save/compare for before/after optimization analysis.

OptionDescription
--phase=<list>Profile categories to measure as a CSV (required, e.g. parse,transform). all/none are not allowed
--iterations=<n>Iteration count (default: 100, must be ≥ 1)
--warmup=<n>Warmup runs before measured runs (default: 10)
--save=<path>Save the run as a baseline JSON
--compare=<path>Compare against an existing baseline JSON
--format=<fmt>Output format — table|tree|json|csv (default: table)
--profile-level=<level>Profile detail level (summary|detailed|per-module|per-pass)
Terminal window
zntc bench --phase=parse,transform --iterations=200 --warmup=20 src/large.ts
zntc bench --phase=parse --save=baseline.json src/main.ts
zntc bench --phase=parse --compare=baseline.json src/main.ts
  • JS API (@zntc/core) in packages/core/index.ts provides the same options programmatically.
  • Surface-level option coverage is listed in the Options Matrix.
  • Visualize --metafile output on the Metafile Analyze page.
  • Use @zntc/vite-plugin or vitePlugin() for the Vite adapter.
  • Use @zntc/rspack-loader for the Rspack / Webpack 5 adapter. (guide)
  • Unsupported options and future plans: docs/ROADMAP.md.