Node API
Purpose and Scope
The @tailwindcss/node package is the Node.js integration layer around the core tailwindcss compiler. It is intended for build tools, CLIs, framework plugins, and other Node-based runtimes that need to compile Tailwind CSS while resolving local JavaScript modules, resolving imported stylesheets, tracking dependencies for rebuilds, rewriting URLs, optimizing generated CSS, and optionally reporting instrumentation data. The package is published separately from the core framework so Node-specific behavior can live outside the browser-safe compiler surface while still re-exporting compiler feature flags and shared build primitives.
Sources: packages/@tailwindcss-node/package.json, packages/@tailwindcss-node/src/index.ts, packages/@tailwindcss-node/src/compile.ts
Use this API when you are writing an integration rather than authoring application CSS directly. The official class-detection model explains that Tailwind scans source files as plain text, keeps tokens that map to known utilities, and generates CSS only for classes actually used. The Node API does not change that model; instead, it gives Node tools the surrounding services the compiler needs in real projects, including module loading for configuration-like inputs, stylesheet loading, source detection root validation, and dependency callbacks that a watcher can use to know what should trigger recompilation.
Sources: packages/@tailwindcss-node/src/compile.ts
Relevant Source Files
packages/@tailwindcss-node/package.json— Declares the published package name, dependency set, build scripts, files, package exports, and publish-time export mapping for ESM, CommonJS,require-cache, andesm-cache-loader.packages/@tailwindcss-node/src/index.ts— Defines the public barrel module, re-exporting compile, optimize, instrumentation, path normalization, source-map helpers, and environment helpers while registering the ESM cache loader hook when supported by the current Node runtime.packages/@tailwindcss-node/src/compile.ts— Implements Node-aware compilation wrappers, theCompileOptionsandResolvercontracts, module and stylesheet loading hooks, URL rewriting, dependency reporting, and source detection root validation.packages/@tailwindcss-node/src/optimize.ts— Implements the exported CSS optimizer around Lightning CSS, source-map remapping, warning filtering, browser targets, and Tailwind-specific post-processing.packages/@tailwindcss-node/src/instrumentation.ts— Implements theInstrumentationclass used to count hits, time nested spans, emit debug reports, and integrate withSymbol.disposeandSymbol.asyncDispose.
Package Entry Points and Runtime Registration
The package metadata publishes the main entry point as @tailwindcss/node, with type, import, and require mappings. It also exposes @tailwindcss/node/require-cache and @tailwindcss/node/esm-cache-loader, which are supporting entry points for module cache behavior. In development source form, the same export map points to TypeScript sources and the .cts CommonJS adapters. The dependency list is a useful summary of what this layer owns: enhanced resolution, Jiti-backed loading, Lightning CSS optimization, MagicString edits, source-map remapping, and the workspace tailwindcss compiler dependency.
Sources: packages/@tailwindcss-node/package.json
The public index is intentionally broad but shallow. It re-exports compile, instrumentation, normalize-path, optimize, source-maps, and an env namespace. On load, it also performs Node runtime setup for ESM cache busting. Bun is excluded because Bun populates require.cache for ESM modules, so the extra module hook is unnecessary there. For Node, the package prefers Module.registerHooks when available and falls back to Module.register with the package’s esm-cache-loader when the newer hook API is not present. This matters for watch-mode integrations because included files can be reloaded by cache-busting URLs even when some ESM dependencies remain cached.
Sources: packages/@tailwindcss-node/src/index.ts
Compile API
The central compile surface is compile(css, options) for CSS strings and compileAst(ast, options) for already-parsed Tailwind AST nodes. Both call the core tailwindcss compiler with Node-aware hooks produced from CompileOptions, then validate the compiler’s source detection root before returning the compiler object. __unstable__loadDesignSystem(css, { base }) is also exported for loading a design system with the same module and stylesheet resolution behavior, but its name signals that it should be treated as a lower-stability integration hook rather than the everyday build entry point.
Sources: packages/@tailwindcss-node/src/compile.ts
CompileOptions requires a base directory and an onDependency(path) callback. It optionally accepts from, shouldRewriteUrls, polyfills, customCssResolver, and customJsResolver. The base value anchors stylesheet and module resolution, while from identifies the input file when available. The dependency callback is the bridge between Tailwind compilation and an external watcher: when Tailwind loads modules or stylesheets, the integration can record those paths and invalidate its build graph later. Custom resolvers let a host tool participate in resolution before or instead of the default Node-oriented resolver path.
Sources: packages/@tailwindcss-node/src/compile.ts
Stylesheet loading and JavaScript module loading are passed into the core compiler as loadStylesheet and loadModule. When shouldRewriteUrls is enabled, loaded stylesheet content is passed through URL rewriting using the project root and the stylesheet base, preserving correct relative asset references when CSS files are imported from different locations. Module loading distinguishes package-like identifiers from relative identifiers only in cache behavior: non-relative modules are imported normally, while relative modules are imported with a timestamp query and inspected for dependencies. That pattern gives local project files stronger watch-mode freshness than stable external package imports.
Sources: packages/@tailwindcss-node/src/compile.ts
The compile wrapper also enforces a source detection safety check. If the returned compiler reports a root and that root is not none, the Node layer walks the root pattern until the first glob symbol and verifies that the concrete base directory exists. If the directory is absent, compilation fails with an explicit source(...) error. This is a Node integration concern because build tools should surface a misconfigured source root early, before the watcher silently scans nothing or the user assumes Tailwind missed complete class names.
Sources: packages/@tailwindcss-node/src/compile.ts
Optimization and Source Maps
The optimize(input, options) function is the Node package’s CSS post-processing entry point. OptimizeOptions includes file, minify, and map; TransformResult returns generated code and an optional map. The implementation runs Lightning CSS with custom media enabled, deep selector combinator support, nesting and media-query transforms included, and selected transforms excluded, including logical properties, :dir, and light-dark. It also sets explicit browser targets for Safari, iOS Safari, Firefox, and Chrome, which makes optimization behavior deterministic for integrations that invoke this package.
Sources: packages/@tailwindcss-node/src/optimize.ts
Optimization runs Lightning CSS twice so adjacent rules can be merged after nesting expansion. Between and after transforms, source maps are carried forward when an input map exists. The function filters warnings that Tailwind-integrated frameworks commonly produce intentionally, such as unknown pseudo-class warnings for Vue-style :deep(), :slotted(), and :global(), plus an allowed @position-try at-rule warning. Other Lightning CSS warnings are displayed outside tests with contextual source snippets, giving users actionable output while avoiding noise for known nonstandard framework syntax.
Sources: packages/@tailwindcss-node/src/optimize.ts
After Lightning CSS finishes, the optimizer applies a Tailwind-specific compatibility fix for media query range syntax by replacing @media not ( with @media not all and (. The code uses MagicString for the edit and remapping support so source maps remain accurate after this textual transformation. That detail is important for build tools because generated CSS may be minified, transformed, and mapped back through several stages; preserving map quality is part of the public value of using @tailwindcss/node instead of composing raw compiler and optimizer calls manually.
Sources: packages/@tailwindcss-node/src/optimize.ts
Instrumentation API
Instrumentation is a small disposable reporting utility for counting events and timing nested work. It defaults to reporting according to the package environment debug flag and writes reports to stderr unless a different flush function is supplied. hit(label) increments a counter, start(label) and end(label) maintain a timer stack, track(label) returns an object with dispose hooks, and span(label, fn) wraps synchronous or promise-returning work. The class guards timer correctness by throwing when end() receives a label that does not match the most recent timer.
Sources: packages/@tailwindcss-node/src/instrumentation.ts
The report format separates plain hits from timers and represents nested spans using //-joined labels internally. Before reporting, pending timers are automatically ended from the stack, which helps integrations produce useful diagnostics even if a branch exits early. reset() clears counters, timers, and pending stack entries after output. The file also ensures Symbol.dispose and Symbol.asyncDispose exist, allowing the API to work with TypeScript 5.2-style disposal patterns even in runtimes where those symbols are not predefined.
Sources: packages/@tailwindcss-node/src/instrumentation.ts
Compact Reference
| API | Kind | Contract | Notes |
|---|---|---|---|
compile(css, options) | Function | Compiles a CSS string through the core compiler with Node resolution hooks | Validates the source detection root before returning |
compileAst(ast, options) | Function | Compiles Tailwind AST nodes with the same Node hooks | Accepts AstNode[] from the core AST model |
__unstable__loadDesignSystem(css, { base }) | Function | Loads a design system using Node module and stylesheet loaders | Name indicates lower stability |
CompileOptions.base | Required option | Base directory for resolution and URL handling | Required by compile wrappers |
CompileOptions.onDependency | Required callback | Receives dependency paths discovered during loading | Used by watch-mode integrations |
CompileOptions.shouldRewriteUrls | Optional option | Enables URL rewriting for loaded stylesheets | Uses root and stylesheet base |
CompileOptions.customCssResolver | Optional resolver | Resolves stylesheet IDs | Resolver returns a path, false, or undefined |
CompileOptions.customJsResolver | Optional resolver | Resolves JavaScript module IDs | Used by loadModule |
optimize(input, options) | Function | Optimizes CSS and optionally preserves source maps | Returns { code, map } |
OptimizeOptions.file | Optional option | Filename passed to Lightning CSS | Defaults to input.css |
OptimizeOptions.minify | Optional option | Enables minified output | Defaults to false |
OptimizeOptions.map | Optional option | Input source map before optimization | Enables output map when present |
Instrumentation | Class | Counts hits, times spans, reports and resets | Supports disposable and async-disposable tracking |
Integration Guidance
A typical integration should call compile during setup, pass its project root as base, provide an onDependency callback that records loaded files in the host build graph, and enable URL rewriting when imported CSS assets need to remain correct after bundling. After the compiler generates CSS for detected candidates, call optimize when the integration owns final CSS output or minification. Use Instrumentation around expensive phases when debugging build performance, especially in watch mode where repeated dependency resolution, source scanning, and CSS optimization can have different cost profiles.
Sources: packages/@tailwindcss-node/src/compile.ts, packages/@tailwindcss-node/src/optimize.ts, packages/@tailwindcss-node/src/instrumentation.ts
For next steps, read the core tailwindcss package API to understand what the compiler returns, then read the Vite, PostCSS, CLI, and Webpack integration pages to see how Node-level primitives are embedded in public tools. If the user-facing problem is missing generated utilities, start with class detection concepts first: make sure complete class names exist in source text, then use dependency tracking and source root validation from this package to confirm that the right files are being watched and compiled.