Config File
Set up and configure Packem using configuration files
Config File
Packem supports configuration files to customize your build process. While many options can be set via CLI flags, configuration files provide a more maintainable and powerful way to configure complex builds.
Configuration File Discovery
Packem automatically discovers configuration files in the following order:
packem.config.tspackem.config.jspackem.config.mjspackem.config.cjs
TypeScript configuration files (packem.config.ts) are recommended as they provide type safety and autocomplete support.
Basic Configuration
TypeScript Configuration
// packem.config.ts
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
// The transformer is imported and passed as a value
transformer,
// Generate source maps for every output
sourcemap: true,
})The transformer is imported and passed as a value, not selected with a
string. Swap the import to choose a different one — e.g.
@visulima/packem/transformer/swc, /oxc, or /sucrase. Output formats are
derived from your package.json; you rarely need to set rollup.output
manually.
JavaScript Configuration
// packem.config.js
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
transformer,
})CommonJS Configuration
// packem.config.cjs
const { defineConfig } = require('@visulima/packem/config')
const transformer = require('@visulima/packem/transformer/esbuild')
module.exports = defineConfig({
transformer,
})Configuration Schema
The defineConfig function provides full TypeScript support and validation:
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
// Entry points (optional - auto-detected from package.json)
entries?: BuildEntry[] | string[]
// The transformer instance, imported and passed as a value
transformer?: TransformerFn
// Generate source maps for every output
sourcemap?: boolean
// Minify the output (the active transformer performs the minification)
minify?: boolean
// Target runtime environment
runtime?: 'node' | 'browser' | 'edge-light' | 'react-server' | 'bun' | 'deno' | 'workerd' | 'electron' | 'react-native'
// Browserslist queries used for transpilation
browserTargets?: string[]
// Rollup configuration. Transformer-specific options and CSS options
// nest here, NOT at the top level.
rollup?: {
plugins?: Plugin[]
// Transformer-specific options
esbuild?: EsbuildOptions | false
swc?: SwcPluginConfig | false
oxc?: OxcOptions | false
sucrase?: SucrasePluginConfig | false
// CSS configuration (see the CSS guide for the full StyleOptions shape)
css?: {
mode?: 'inject' | 'extract' | 'emit' | 'inline'
autoModules?: boolean | RegExp | ((id: string) => boolean)
loaders?: Loader[]
sourceMap?: boolean | 'inline'
// ... other CSS options
}
// Watcher options, used when the build runs with --watch
watch?: WatcherOptions | false
// ... other Rollup options
}
// Build hooks (each receives the build context)
hooks?: {
'build:before'?: (context) => void | Promise<void>
'build:done'?: (context) => void | Promise<void>
// ... other hooks (rollup:options, validate:before, …)
}
})Advanced Configuration
Conditional Configuration
Configure different options based on environment:
import { defineConfig } from '@visulima/packem/config'
import esbuildTransformer from '@visulima/packem/transformer/esbuild'
import swcTransformer from '@visulima/packem/transformer/swc'
const isDevelopment = process.env.NODE_ENV === 'development'
export default defineConfig({
// Import each transformer you want to switch between, then pick one
transformer: isDevelopment ? esbuildTransformer : swcTransformer,
sourcemap: isDevelopment,
rollup: {
plugins: [
// Development plugins
...(isDevelopment ? [devPlugin()] : []),
// Production plugins
...(isDevelopment ? [] : [prodPlugin()])
]
}
})Function-Based Configuration
Use a function for dynamic configuration:
The configuration function receives (environment, mode), where
environment is "production" | "development" | undefined and mode is
"build" | "jit" | "watch":
import { defineConfig } from '@visulima/packem/config'
import esbuildTransformer from '@visulima/packem/transformer/esbuild'
import swcTransformer from '@visulima/packem/transformer/swc'
export default defineConfig((environment, mode) => {
const isProduction = environment === 'production'
return {
transformer: isProduction ? swcTransformer : esbuildTransformer,
sourcemap: !isProduction,
rollup: {
// CSS options nest under `rollup.css`
css: {
mode: isProduction ? 'extract' : 'inject',
autoModules: true
}
}
}
})Async Configuration
The configuration function may be async and return a Promise:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig(async () => {
const { default: extraPlugins } = await import('./build/plugins.js')
return {
transformer,
rollup: {
plugins: extraPlugins,
},
}
})Configuration Merging
Packem automatically merges configurations from multiple sources:
- Default configuration - Sensible defaults
- Configuration file - Your custom configuration
- CLI flags - Command-line overrides
// packem.config.ts
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
transformer,
outDir: 'dist',
})# CLI flags override config file
packem build --outDir buildEnvironment Variables
Access environment variables in your configuration:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
transformer,
outDir: process.env.PACKEM_OUTPUT_DIR || 'dist',
sourcemap: process.env.NODE_ENV !== 'production',
})To inject values into the bundled source at compile time (rather than into
the config itself), use .env files or the --env.* CLI flag described below —
Packem replaces matching process.env.* references in your code.
Loading from .env Files
You can load compile-time environment variables from .env files:
export default defineConfig({
// Path to the .env file (relative to project root or absolute)
envFile: '.env',
// Prefix to filter environment variables (default: 'PACKEM_')
// Only variables starting with this prefix will be loaded
envPrefix: 'PACKEM_',
// ...
})CLI Options:
You can also specify these via command-line flags:
# Load from .env file
packem build --env-file .env
# Custom prefix
packem build --env-file .env --env-prefix BUILD_
# CLI options override config file options
packem build --env-file .env.production --env-prefix PROD_How it works:
- Variables are loaded from the specified
.envfile - Only variables matching the
envPrefixare included (default:PACKEM_) - Variables are replaced at compile-time in your source code
- CLI
--env.*variables override.envfile variables
Example:
# .env file
PACKEM_API_URL=https://api.example.com
PACKEM_VERSION=1.0.0
OTHER_VAR=ignored # Not loaded (doesn't match prefix)// src/index.ts
export const apiUrl = process.env.PACKEM_API_URL;
export const version = process.env.PACKEM_VERSION;After building, these will be replaced with their actual values at compile-time.
Configuration Validation
Packem validates your configuration and provides helpful error messages:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
transformer,
runtime: 'invalid', // ❌ TypeScript error: not a valid runtime
rollup: {
output: {
format: 'unknown' // ❌ TypeScript error
}
}
})Custom Configuration Location
Specify a custom configuration file location:
packem build --config ./configs/packem.config.tsPACKEM_CONFIG=./configs/packem.config.ts packem buildConfiguration Presets
Packem provides built-in presets for common use cases, and you can also create your own reusable configuration presets.
Built-in Presets
React Preset
The React preset configures Babel to handle React JSX transformation. Babel runs before your main transformer (esbuild/SWC/etc.), transforming JSX into JavaScript that the transformer can then process. TypeScript is handled by the transformer via parser plugins, not by Babel.
Quick Setup:
Use the add command to automatically configure React:
npx packem add reactThis will automatically set up the React preset and install all necessary dependencies.
Basic Usage:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: 'react',
transformer,
})With React Compiler:
import { defineConfig } from '@visulima/packem/config'
import { createReactPreset } from '@visulima/packem/config/preset/react'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: createReactPreset({
compiler: true
}),
transformer,
})With React Compiler Annotation Mode:
import { defineConfig } from '@visulima/packem/config'
import { createReactPreset } from '@visulima/packem/config/preset/react'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: createReactPreset({
compiler: {
compilationMode: 'annotation',
panicThreshold: 'critical_errors'
}
}),
transformer,
})Custom Options:
import { defineConfig } from '@visulima/packem/config'
import { createReactPreset } from '@visulima/packem/config/preset/react'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: createReactPreset({
compiler: true,
plugins: [], // Additional Babel plugins
presets: [] // Additional Babel presets
}),
transformer,
})How it works:
- Babel (runs first): Transforms JSX → JS (handles JSX transformation with React Compiler if enabled)
- Transformer (esbuild/SWC/etc.): Processes the code and handles TypeScript transformation via parser plugins
- Rollup plugins: Can parse the code since it's pure JavaScript
React Preset Options:
compiler: Enable React Compiler optimizationboolean: Enable with default optionsobject: Configure compiler optionscompilationMode:"infer"(default) or"annotation"- In annotation mode, only files with"use memo"directive are processedpanicThreshold:"critical_errors"(default) or"all_errors"
plugins: Additional Babel plugins to includepresets: Additional Babel presets to include
Note: The React preset automatically excludes react and react-dom from unused dependency validation, as these are typically peer dependencies. TypeScript is handled by the transformer (esbuild/SWC/etc.) via parser plugins, not by Babel. This matches the approach used by @vitejs/plugin-react.
SolidJS Preset
The SolidJS preset configures Babel to handle SolidJS JSX transformation. Babel runs before your main transformer (esbuild/SWC/etc.), transforming JSX into JavaScript that the transformer can then process. TypeScript is handled by the transformer via parser plugins, not by Babel.
Quick Setup:
Use the add command to automatically configure SolidJS:
npx packem add solidThis will automatically set up the SolidJS preset and install all necessary dependencies.
Basic Usage:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: 'solid',
transformer,
})With Custom Solid Options:
import { defineConfig } from '@visulima/packem/config'
import { createSolidPreset } from '@visulima/packem/config/preset/solid'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: createSolidPreset({
solidOptions: {
generate: 'ssr',
hydratable: true,
moduleName: 'solid-js/web'
}
}),
transformer,
})With Custom Babel Options:
import { defineConfig } from '@visulima/packem/config'
import { createSolidPreset } from '@visulima/packem/config/preset/solid'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: createSolidPreset({
solidOptions: {
generate: 'dom'
},
env: {
targets: 'last 2 years'
},
typescript: true
}),
transformer,
})How it works:
- Babel (runs first): Transforms JSX → JS (handles JSX transformation with Solid preset)
- Transformer (esbuild/SWC/etc.): Processes the code and handles TypeScript transformation via parser plugins
- Rollup plugins: Can parse the code since it's pure JavaScript
Solid Preset Options:
solidOptions: Configure SolidJS-specific optionsmoduleName: Runtime module name (default:"solid-js/web")generate: Output mode -"dom"(default) or"ssr"for server-side renderinghydratable: Enable hydratable markers (default:false)delegateEvents: Enable automatic event delegation (default:true)wrapConditionals: Enable smart conditional detection (default:true)contextToCustomElements: Set render context on Custom Elements (default:true)builtIns: Array of Component exports to auto-import
env: Enable @babel/preset-env (default:true)boolean: Enable with default targets ("last 2 years")object: Configure with custom targets
plugins: Additional Babel plugins to includepresets: Additional Babel presets to include
Note: The Solid preset automatically excludes solid-js, solid-js/web, and solid-js/store from unused dependency validation, as these are typically peer dependencies. TypeScript is handled by the transformer (esbuild/SWC/etc.) via parser plugins, not by Babel.
Vue Preset
The Vue preset configures Rollup with unplugin-vue to handle Vue 3 Single File Components (SFCs). The plugin processes .vue files and compiles them for Rollup bundling.
Quick Setup:
Use the add command to automatically configure Vue:
npx packem add vueThis will automatically set up the Vue preset and install all necessary dependencies.
Basic Usage:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: 'vue',
transformer,
})With Custom Options:
import { defineConfig } from '@visulima/packem/config'
import { createVuePreset } from '@visulima/packem/config/preset/vue'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: createVuePreset({
pluginOptions: {
customElement: true,
include: [/\.vue$/],
exclude: [/\.vue\.test\.vue$/],
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('my-')
}
}
}
}),
transformer,
})How it works:
- Rollup Plugin (unplugin-vue): Processes
.vuefiles, extracts<script>,<template>, and<style>blocks - Transformer (esbuild/SWC/etc.): Processes the compiled JavaScript and handles TypeScript transformation
- CSS Processing: Styles are handled by Packem's CSS processing pipeline
Vue Preset Options:
pluginOptions: Configure the Vue plugin optionscustomElement: Enable custom elements mode (default:false)include: Include patterns for Vue files (default:[/\.vue$/])exclude: Exclude patterns for Vue filestemplate: Template compiler optionscompilerOptions: Vue template compiler optionsisCustomElement: Function to determine if a tag is a custom element
Note: The Vue preset automatically excludes vue from unused dependency validation, as it's typically a peer dependency.
Svelte Preset
The Svelte preset configures Rollup with rollup-plugin-svelte to handle Svelte components. The plugin processes .svelte files and compiles them for Rollup bundling.
Quick Setup:
Use the add command to automatically configure Svelte:
npx packem add svelteThis will automatically set up the Svelte preset and install all necessary dependencies.
Basic Usage:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: 'svelte',
transformer,
})With Custom Options:
import { defineConfig } from '@visulima/packem/config'
import { createSveltePreset } from '@visulima/packem/config/preset/svelte'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
preset: createSveltePreset({
pluginOptions: {
compilerOptions: {
generate: 'ssr',
hydratable: true,
customElement: false
},
include: [/\.svelte$/],
exclude: [/\.svelte\.test\.svelte$/],
preprocess: {
// Preprocessor options
}
}
}),
transformer,
})How it works:
- Rollup Plugin (rollup-plugin-svelte): Processes
.sveltefiles, compiles components to JavaScript - Transformer (esbuild/SWC/etc.): Processes the compiled JavaScript and handles TypeScript transformation
- CSS Processing: Styles are extracted and handled by Packem's CSS processing pipeline
Svelte Preset Options:
pluginOptions: Configure the Svelte plugin optionscompilerOptions: Svelte compiler optionsgenerate: Output mode -"dom"(default) or"ssr"for server-side renderinghydratable: Enable hydratable markers (default:false)customElement: Compile components to custom elements (default:false)dev: Enable dev mode (default:false)
include: Include patterns for Svelte files (default:[/\.svelte$/])exclude: Exclude patterns for Svelte filespreprocess: Preprocessor options for Svelte components
Note: The Svelte preset automatically excludes svelte from unused dependency validation, as it's typically a peer dependency.
Custom Presets
Create reusable configuration presets:
// configs/presets.ts
import transformer from '@visulima/packem/transformer/esbuild'
export const libraryPreset = {
transformer,
sourcemap: true,
declaration: true,
hooks: {
'build:before': async () => {
console.log('Preset hook: Preparing library build')
}
}
}
export const cliPreset = {
transformer,
outDir: 'bin',
}// packem.config.ts
import { defineConfig } from '@visulima/packem/config'
import { libraryPreset } from './configs/presets'
export default defineConfig({
...libraryPreset,
// Override specific options
rollup: {
...libraryPreset.rollup,
css: {
mode: 'extract'
}
},
// Hooks from preset are automatically merged
// You can add your own hooks or override preset hooks
hooks: {
'build:done': async () => {
console.log('User hook: Build completed')
}
// Preset's 'build:before' hook is still registered
}
})Hooks from presets are automatically merged with your configuration. If you define the same hook in both, your hook will take precedence.
Configuration Composition
defineConfig takes a plain object, so you can compose configuration from
multiple sources with object spreading — later spreads win:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/swc'
import baseConfig from './base.config'
import cssConfig from './css.config'
export default defineConfig({
...baseConfig,
...cssConfig,
// Additional overrides
transformer,
rollup: {
...baseConfig.rollup,
...cssConfig.rollup,
},
})IDE Support
TypeScript IntelliSense
Get full autocomplete and type checking in your configuration:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
transformer,
rollup: {
output: {
// TypeScript autocompletes Rollup options here
format: '|' // Shows: 'es' | 'cjs' | 'iife' | 'umd' | 'system'
}
}
})Configuration Schema
Import the BuildConfig type for better IDE support:
import { defineConfig } from '@visulima/packem/config'
import type { BuildConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
const config: BuildConfig = {
transformer,
sourcemap: true,
}
export default defineConfig(config)Debugging Configuration
Enable debug mode to see the resolved configuration:
# Debug configuration resolution
PACKEM_DEBUG=1 packem build
# Debug specific areas
PACKEM_DEBUG=config,rollup packem buildOr programmatically:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
debug: true, // Enable debug logging
transformer,
// ... rest of config
})Configuration Examples
React Library
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
transformer,
externals: ['react', 'react-dom'],
rollup: {
esbuild: {
jsx: 'automatic',
jsxImportSource: 'react'
}
}
})Node.js CLI Tool
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
transformer,
rollup: {
output: {
banner: '#!/usr/bin/env node'
}
}
})Library with CSS
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
transformer,
externals: ['express', 'mongoose'],
rollup: {
css: {
mode: 'extract',
autoModules: true
}
}
})Related Options
- Entry - Configure entry points
- Output Format - Control output formats
- Transformers - Choose and configure transformers
- Hooks - Build lifecycle hooks