Configuration
@utoo/pack can be configured with utoopack.json, utoopack.config.mjs, or the Node API.
Configuration Files
utoopack.json
{
"$schema": "@utoo/pack/config_schema.json",
"mode": "production",
"entry": [
{
"import": "./src/index.ts",
"html": {
"template": "./index.html"
}
}
],
"output": {
"path": "./dist",
"filename": "[name].[contenthash:8].js",
"chunkFilename": "[name].[contenthash:8].js",
"clean": true
}
}Use utoopack.json when your config is fully JSON-serializable. Use utoopack.config.* when you want type inference or JS-based composition. The config-file form can also carry runtime-only UserConfig fields such as processEnv, watch, dev, buildId, tracing, packPath, projectPath, and rootPath.
Top-level Options
| Option | Description |
|---|---|
mode | Build mode: development or production |
target | Target environment |
entry | Entry points, HTML generation, and library output |
output | Output path, filename templates, public path, asset copying |
resolve | Aliases and extension resolution |
define | Build-time constant replacement |
provider | Auto-provide modules, similar to Webpack ProvidePlugin |
externals | Keep dependencies out of the bundle |
module | Custom module rules and loaders |
styles | CSS Modules, Less, Sass, PostCSS, Emotion, styled-components, styled-jsx |
images | Asset inlining behavior |
react | JSX runtime and React transform options |
mdx | Rust MDX transform options |
reactCompiler | Rust React Compiler options |
optimization | Minification, tree shaking, split chunks, import transforms |
devServer | Host, port, HTTPS, HMR, proxy |
server | Server entries, Server Functions, and server output |
sourceMaps | Enable source maps |
stats | Emit build stats |
persistentCaching | Reuse cache across runs |
turbopackMemoryEviction | Memory eviction mode for the persistent cache |
nodePolyfill | Polyfill Node.js built-ins for browser builds |
swcPlugins | Custom SWC plugins |
pluginRuntimeStrategy | Loader / plugin process model |
experimental | Compatibility entry for reactCompiler and swcPlugins |
Core Configuration
mode and target
Build mode affects optimizations and defaults. target selects the output runtime.
{
"mode": "production",
"target": "browser"
}| Value | Description |
|---|---|
development | Faster builds, better debugging, HMR enabled |
production | Optimized output, minification, tree shaking |
entry
Define application entry points, HTML generation, and library output.
{
"entry": [
{
"name": "main",
"import": "./src/index.ts",
"library": {
"name": "MyBundle",
"export": ["default"]
},
"html": {
"template": "./index.html",
"filename": "index.html",
"title": "My App",
"inject": "body",
"scriptLoading": "module"
}
}
]
}output
Configure output path, file naming, static copying, and runtime asset URLs.
{
"output": {
"path": "./dist",
"type": "standalone",
"filename": "[name].[contenthash:8].js",
"chunkFilename": "[name].[contenthash:8].js",
"cssFilename": "[name].[contenthash:8].css",
"cssChunkFilename": "[name].[contenthash:8].css",
"assetModuleFilename": "assets/[name].[contenthash:8][ext]",
"publicPath": "/",
"crossOriginLoading": "anonymous",
"copy": ["./public"],
"chunkLoadingGlobal": "TURBOPACK",
"clean": true,
"entryRootExport": "AppExports"
}
}| Option | Description |
|---|---|
path | Output directory |
type | Output type: standalone or export |
filename | Entry chunk filename template |
chunkFilename | Non-entry chunk filename template |
cssFilename | Main CSS filename template |
cssChunkFilename | CSS chunk filename template |
assetModuleFilename | Asset filename template |
publicPath | Public URL prefix for assets; also supports runtime and auto |
crossOriginLoading | Cross-origin attribute for lazy chunks |
copy | Copy static files into the output directory |
chunkLoadingGlobal | Global variable used by the runtime to load chunks |
clean | Clean output directory before build |
entryRootExport | Expose entry exports on window / globalThis |
Use publicPath: "runtime" to read the runtime prefix from globalThis.publicPath, or publicPath: "auto" to infer it from the currently loaded script URL.
define
Build-time variable replacement.
{
"define": {
"process.env.NODE_ENV": "\"production\"",
"__VERSION__": "\"1.0.0\""
}
}provider
Automatically inject modules, similar to Webpack ProvidePlugin.
{
"provider": {
"$": "jquery",
"Buffer": ["buffer", "Buffer"]
}
}externals
Exclude dependencies from the bundle.
{
"externals": {
"react": "React",
"react-dom": "ReactDOM",
"lodash-es": {
"root": "_",
"type": "global"
}
}
}Externals support simple string globals, script, commonjs, esm, global, and promise forms, plus more advanced subpath configuration.
resolve
Configure module resolution. resolve.alias rewrites an import request to another module or path, using Turbopack-style alias rules .
{
"resolve": {
"alias": {
"react": "preact/compat",
"@/*": "./src/*",
"legacy/": "./src/legacy/",
"runtime/*": ["./src/runtime/*", "./fallback/runtime/*"]
},
"extensions": [".ts", ".tsx", ".js", ".jsx"]
}
}resolve.alias accepts this shape:
type ResolveAlias =
Record<string, string | string[] | Record<string, string | string[]>>Matching rules:
| Alias | Matches | Does not match |
|---|---|---|
"foo": "./src/foo" | import "foo" | import "foo/bar" |
"foo/*": "./src/foo/*" | import "foo/bar" and deeper subpaths | import "foo" |
"foo/": "./src/foo/" | Same as "foo/*": "./src/foo/*" | import "foo" |
Use * when you want to carry the matched subpath into the replacement. The * can match across path separators, so "@/*": "./src/*" resolves imports such as @/components/Button.
Alias values can be:
| Value | Behavior |
|---|---|
string | Rewrite to a single package or path |
string[] | Try multiple candidates in order |
| condition object | Pick a value by condition, commonly browser, with default as the fallback |
Relative path values are resolved from the project root, for example "./src/foo". Absolute paths inside the project are normalized to project-relative paths. Avoid aliases that point outside the project directory.
import { defineConfig } from '@utoo/pack';
export default defineConfig({
resolve: {
alias: {
// Exact replacement
lodash: 'lodash-es',
// Subpath replacement
'@/*': './src/*',
// Directory shortcut
'components/': './src/components/',
// Multiple candidates
'runtime/*': ['./src/runtime/*', './fallback/runtime/*'],
// Conditional alias
env: {
browser: './src/env.browser.ts',
default: './src/env.node.ts',
},
},
extensions: ['.ts', '.tsx', '.js', '.jsx'],
},
});Migrating from Webpack alias
The biggest difference is subpath matching. In Webpack, an alias such as foo: path.resolve(__dirname, 'src/foo') is commonly used to cover both foo and foo/bar. In Utoopack, a plain key is exact. Add /* or use the trailing slash shortcut when you want subpath imports.
| Webpack | Utoopack |
|---|---|
foo: path.resolve(__dirname, 'src/foo') for import "foo" | "foo": "./src/foo" |
foo: path.resolve(__dirname, 'src/foo') for import "foo/bar" | "foo/*": "./src/foo/*" or "foo/": "./src/foo/" |
'@': path.resolve(__dirname, 'src') for import "@/Button" | "@/*": "./src/*" |
react: 'preact/compat' | "react": "preact/compat" |
Webpack’s $ suffix marks an exact alias, for example foo$: './src/foo'. Utoopack does not need that suffix because exact matching is the default:
{
"resolve": {
"alias": {
"foo": "./src/foo"
}
}
}This only affects:
import "foo"It does not affect:
import "foo/bar"To cover subpaths, use:
{
"resolve": {
"alias": {
"foo/*": "./src/foo/*"
}
}
}Or the directory shortcut:
{
"resolve": {
"alias": {
"foo/": "./src/foo/"
}
}
}module
Define loader-based module rules. Rule objects can include loaders, condition, and type.
{
"module": {
"rules": {
"*.md": ["raw-loader"],
"*.svg": [
{
"loaders": [
{
"loader": "@svgr/webpack",
"options": {
"icon": true
}
}
]
}
]
}
}
}styles
Configure built-in style processing.
{
"styles": {
"autoCssModules": true,
"cssModules": {
"localIdentName": "[local]__[hash:base64:6]"
},
"postcss": {},
"less": {
"loader": "less-loader",
"implementation": "less"
},
"sass": {
"implementation": "sass"
},
"inlineCss": {
"injectType": "styleTag"
},
"emotion": {
"autoLabel": "dev-only"
},
"styledComponents": {
"displayName": true,
"ssr": true
},
"styledJsx": {
"useLightningcss": true
}
}
}Use styles.cssModules.localIdentName to customize the CSS Modules class-name template. Use styles.less.loader to select a custom Less loader; implementation selects the Less implementation, and additional fields are forwarded to the loader.
images
Configure image inlining.
{
"images": {
"inlineLimit": 8192
}
}react
React transform options.
{
"react": {
"runtime": "automatic",
"importSource": "react",
"absoluteSourceFilename": false
}
}mdx
mdx enables the Rust MDX transform. It accepts a boolean or an object that configures compilation, the JSX runtime, and the MDX syntax mode.
{
"mdx": {
"development": false,
"jsx": false,
"jsxRuntime": "automatic",
"jsxImportSource": "react",
"providerImportSource": "@mdx-js/react",
"mdxType": "gfm"
}
}mdxType supports commonmark and gfm. Use "mdx": true to enable the default configuration.
React Compiler and SWC plugins
reactCompiler accepts a boolean or an object with compilationMode and target for the Rust React Compiler. compilationMode supports infer, annotation, and all; target supports React 18 and 19.
{
"reactCompiler": {
"compilationMode": "infer",
"target": "19"
},
"swcPlugins": [
["swc-plugin-name", {}]
]
}experimental.reactCompiler and experimental.swcPlugins remain supported. Top-level reactCompiler takes precedence over experimental.reactCompiler; swcPlugins from the top level and experimental are merged.
optimization
{
"optimization": {
"minify": true,
"extractComments": true,
"treeShaking": true,
"moduleIds": "deterministic",
"splitChunks": {
"js": {
"minChunkSize": 50000,
"maxChunkCountPerGroup": 40,
"maxMergeChunkSize": 200000
}
},
"cssChunking": "graph",
"modularizeImports": {
"lodash": {
"transform": "lodash/{{member}}",
"preventFullImport": true
}
},
"packageImports": ["package-name"],
"transpilePackages": ["shared-ui"],
"removeConsole": {
"exclude": ["error"]
},
"concatenateModules": true,
"removeUnusedExports": true,
"removeUnusedImports": true
}
}| Option | Type | Description |
|---|---|---|
moduleIds | named | deterministic | Module ID generation strategy |
noMangling | boolean | Preserve local variable and function names during minification |
compress | boolean | object | Control compression; object options include passes, sequences, keepClassnames, and keepFnames |
minify | boolean | Minify output code |
extractComments | boolean | Extract legal comments to [file].LICENSE.txt when minifying library output |
treeShaking | boolean | Remove unused code |
splitChunks | object | Configure size and count limits for js / css chunks |
cssChunking | boolean | string | object | CSS chunk grouping algorithm |
modularizeImports | object | Transform package imports with templates, similar to babel-plugin-import |
packageImports | string[] | Optimize package entry points with many exports |
transpilePackages | string[] | Transpile selected dependencies |
removeConsole | boolean | object | Remove console calls, with optional methods retained through exclude |
concatenateModules | boolean | Concatenate modules to reduce chunk count |
removeUnusedExports | boolean | Remove unused exports; defaults off in development and on in production |
removeUnusedImports | boolean | Remove unused imports; defaults off in development and on in production |
nestedAsyncChunking | boolean | Enable nested async chunks |
wasmAsAsset | boolean | Inline WASM into the bundle; defaults off and emits static assets instead |
optimization.packageImports
optimization.packageImports optimizes named imports from packages that export many modules. After adding a package, application code can keep importing from the package root while Utoopack loads only the modules that are actually used, reducing module parsing and compilation overhead in development and production builds. The option accepts a string[] and behaves similarly to Next.js optimizePackageImports.
{
"optimization": {
"packageImports": ["package-name"]
}
}Utoopack’s built-in list is maintained with reference to Next.js, but the DEFAULT_OPTIMIZE_PACKAGE_IMPORTS implementation is the source of truth. It currently contains 74 packages or package subpaths:
[
"lucide-react", "date-fns", "lodash-es", "ramda",
"react-bootstrap", "ahooks", "@ant-design/icons",
"@headlessui/react", "@headlessui-float/react",
"@heroicons/react/20/solid", "@heroicons/react/24/solid",
"@heroicons/react/24/outline", "@visx/visx", "@tremor/react",
"rxjs", "@mui/material", "@mui/icons-material", "recharts", "react-use",
"effect", "@effect/schema", "@effect/platform",
"@effect/platform-node", "@effect/platform-browser", "@effect/platform-bun",
"@effect/sql", "@effect/sql-mssql", "@effect/sql-mysql2", "@effect/sql-pg",
"@effect/sql-sqlite-node", "@effect/sql-sqlite-bun",
"@effect/sql-sqlite-wasm", "@effect/sql-sqlite-react-native",
"@effect/rpc", "@effect/rpc-http", "@effect/typeclass",
"@effect/experimental", "@effect/opentelemetry",
"@material-ui/core", "@material-ui/icons", "@tabler/icons-react", "mui-core",
"react-icons/ai", "react-icons/bi", "react-icons/bs", "react-icons/cg",
"react-icons/ci", "react-icons/di", "react-icons/fa", "react-icons/fa6",
"react-icons/fc", "react-icons/fi", "react-icons/gi", "react-icons/go",
"react-icons/gr", "react-icons/hi", "react-icons/hi2", "react-icons/im",
"react-icons/io", "react-icons/io5", "react-icons/lia", "react-icons/lib",
"react-icons/lu", "react-icons/md", "react-icons/pi", "react-icons/ri",
"react-icons/rx", "react-icons/si", "react-icons/sl", "react-icons/tb",
"react-icons/tfi", "react-icons/ti", "react-icons/vsc", "react-icons/wi"
]Packages configured through optimization.packageImports are merged with this built-in list and de-duplicated.
optimization.cssChunking
optimization.cssChunking supports true, loose, and graph. loose (and true) uses the default grouping algorithm. graph uses graph-based grouping and can be configured with estimated request cost and weight distribution.
{
"optimization": {
"cssChunking": {
"type": "graph",
"requestCost": 100000,
"weightDistribution": 0.1
}
}
}false, strict, and { "type": "strict" } are not currently supported by Utoopack and cause the build to fail.
devServer
The local repo currently supports hot, dynamicHmrChunkLists, host, port, https, and proxy here.
{
"devServer": {
"hot": true,
"dynamicHmrChunkLists": true,
"host": "0.0.0.0",
"port": 3000,
"https": false,
"proxy": [
{
"context": ["/api"],
"target": "http://localhost:7001",
"changeOrigin": true,
"pathRewrite": {
"^/api": ""
}
}
]
}
}When dynamicHmrChunkLists is enabled, the runtime registers the corresponding HMR chunk lists as dynamic chunks load.
server
server configures server entries, Server Functions boundaries, and server chunk output. entry accepts a single entry string or an array of named entries. The first item in an entry array is the primary server runtime and receives Server Functions.
{
"server": {
"entry": [
{
"name": "server",
"import": "./src/server.ts"
},
{
"name": "admin-server",
"import": "./src/admin.server.ts"
}
],
"function": {
"clientProxy": "./src/transport.ts",
"serverRegister": "./src/register.ts"
},
"output": {
"path": "./dist/server",
"filename": "[name].[contenthash:8].js",
"chunkFilename": "chunks/[name].[contenthash:8].js"
}
}
}For a single entry, use the shorthand "entry": "./src/server.ts". The clientProxy module must export createServerReference(actionId, name), and the serverRegister module must export registerServerReference(action, actionId, name).
Advanced Options
| Option | Type | Description |
|---|---|---|
sourceMaps | boolean | Enable source maps |
stats | boolean | Enable build statistics output |
nodePolyfill | boolean | Polyfill Node.js built-ins for browser |
persistentCaching | boolean | Enable persistent build cache; enabled by default |
turbopackMemoryEviction | boolean | auto | full | Persistent-cache memory eviction; defaults to auto; false disables it and true is equivalent to full |
swcPlugins | [string, any][] | Custom SWC plugins and their options |
pluginRuntimeStrategy | workerThreads | childProcesses | Run loaders / plugins in worker threads or child processes |
experimental | object | Compatibility entry for reactCompiler and swcPlugins |
Config-file runtime fields
These UserConfig fields can be used in utoopack.config.* to control the build process.
| Option | Type | Description |
|---|---|---|
processEnv | Record<string, string> | Environment variables used during compilation |
watch | object | File-watching options |
dev | boolean | Run in development mode |
buildId | string | Current build ID |
tracing | boolean | Enable default tracing logs; enabled by default |
packPath | string | Absolute path to @utoo/pack |
projectPath | string | Project path |
rootPath | string | Root path, which may differ from the project path in a monorepo |
watch supports enable, pollIntervalMs, ignored, and nodeModulesRegexes. node_modules is ignored by default. Use !node_modules/<regex> entries in ignored, or package-name regular expressions in nodeModulesRegexes, to include selected dependencies in watching.
import { defineConfig } from '@utoo/pack';
export default defineConfig({
entry: [{ import: './src/index.ts' }],
watch: {
enable: true,
pollIntervalMs: 500,
ignored: ['node_modules'],
nodeModulesRegexes: ['rc-.*', '@rc-component/.*'],
},
});Programmatic API
build()
const { build } = require('@utoo/pack');
await build({
config: {
mode: "production",
entry: [{ import: "./src/index.ts" }],
output: { path: "./dist" }
}
});For the full configuration schema, see config_schema.json .