# AfterPack configuration reference

Every option, where to set it, and what it does.

Source: https://www.afterpack.dev/docs/config

AfterPack options can be set in `afterpack.json`, as an environment variable, as a CLI argument or plugin option, or for a specific region of your source (Pro). Each later place overrides the earlier ones.

A build that sets nothing uses the `light` preset. `afterpack.json` is looked up from the working directory upward; the nearest one is used.

An option that takes a list replaces its default list. Items are never added to it, so repeat the defaults you want to keep.

## Protection

How strongly the output is protected.

### preset

A named level of protection. Sets `complexity`, the output size multiplier and the inflation budget together. Setting `complexity` explicitly overrides only that.

- Type: `enum`
- Default: `light`
- Tier: Free
- Scope: program or region (directive)
- Values: `minify`, `light`, `medium`, `hard`, `extreme`
- afterpack.json: `{ "preset": "hard" }`
- CLI: `npx afterpack@latest dist/ --preset=hard`
- env: `AFTERPACK_preset=hard`
- directive: `/* @afterpack preset=hard */`

### complexity

How much protection the engine applies. `0` applies none; higher values let it negotiate more and heavier transformations per build, with no fixed feature-per-level schedule. There is no upper bound, and output size grows with the value.

- Type: `number ≥ 0`
- Default: `the preset's value; light is 2`
- Tier: Free
- Scope: program or region (directive)
- afterpack.json: `{ "complexity": 40 }`
- CLI: `npx afterpack@latest dist/ --complexity=40`
- env: `AFTERPACK_complexity=40`
- directive: `/* @afterpack complexity=40 */`

### inflation.max

The maximum output size as a multiple of the input size. A build that would exceed a value you set fails; left unset, a build that reaches the preset's ladder stops growing and still emits.

- Type: `number ≥ 0, or "unlimited"`
- Default: `the preset's output-size ladder: 1.2 / 2 / 2.5 / 4 / 7`
- Tier: Free
- Scope: program or region (directive)
- afterpack.json: `{ "inflation": { "max": 4 } }`
- CLI: `npx afterpack@latest dist/ --inflation.max=4`
- env: `AFTERPACK_inflation_max=4`
- directive: `/* @afterpack inflation.max=4 */`

### strings.encode

Encodes every string literal so that none remains readable in the output.

- Type: `boolean`
- Default: `true at any positive complexity; false at 0`
- Tier: Free
- Scope: program or region (directive)
- afterpack.json: `{ "strings": { "encode": false } }`
- CLI: `npx afterpack@latest dist/ --strings.encode=false`
- env: `AFTERPACK_strings_encode=false`
- directive: `/* @afterpack strings.encode=false */`

### strings.minLength

The shortest string `strings.encode` encodes. Shorter strings stay readable. Raising it reduces output size at the cost of leaving short literals in the clear.

- Type: `integer ≥ 0`
- Default: `0`
- Tier: Free
- Scope: program
- afterpack.json: `{ "strings": { "minLength": 4 } }`
- CLI: `npx afterpack@latest dist/ --strings.minLength=4`
- env: `AFTERPACK_strings_minLength=4`
- directive: not available — Applies to the whole program; cannot be set per region.

### strings.leaks.max

Fails the build when more than this many readable string literals remain in the output. Unset never fails.

- Type: `integer ≥ 0`
- Default: `unset; the count is reported but never fails a build`
- Tier: Free
- Scope: program
- afterpack.json: `{ "strings": { "leaks": { "max": 0 } } }`
- CLI: `npx afterpack@latest dist/ --strings.leaks.max=0`
- env: `AFTERPACK_strings_leaks_max=0`
- directive: not available — Applies to the whole program; cannot be set per region.

### transforms.<kind>.enabled

Enables or disables one kind of transformation. `false` reliably removes that kind at any complexity; `true` permits it, and the engine still decides per build whether to apply it. `comparisonHardening` and `selfIntegrity` are Pro.

- Type: `boolean`
- Default: `true; the two Pro kinds default to false`
- Tier: Free
- Scope: program
- Kinds: `controlFlowFlatten`, `opaquePredicate`, `mixedBooleanArithmetic`, `integerBytecode`, `crossDependency`, `scopeDeepen`, `objectConstruction`, `stringEncoding`, `comparisonHardening` (Pro), `selfIntegrity` (Pro)
- afterpack.json: `{ "transforms": { "controlFlowFlatten": { "enabled": false } } }`
- CLI: `npx afterpack@latest dist/ --transforms.controlFlowFlatten.enabled=false`
- env: `AFTERPACK_transforms_controlFlowFlatten_enabled=false`
- directive: not available — Applies to the whole program; cannot be set per region.

### regions

Region overrides supplied by a build tool instead of source comments. Each entry names a span of your original source and the keys to override inside it.

- Type: `{ start, end, …keys }[]`
- Default: `[]`
- Tier: Pro
- Scope: program
- afterpack.json: `{ "regions": [{ "start": 1200, "end": 1840, "complexity": 80 }] }`
- CLI: not available — Set it in `afterpack.json` or plugin options.
- env: not available — Set it in `afterpack.json` or plugin options.
- directive: not available — Applies to the whole program; cannot be set per region.

### skip

Drops the region to complexity 0, so no transformation is applied inside it and its string literals stay readable. Identifiers inside it are still renamed.

- Type: `boolean`
- Default: `false`
- Tier: Pro
- Scope: program or region (directive)
- Note: Identifier renaming applies to the whole program and has no per-region form. To keep a name, list it in `identifiers.reserved`.
- afterpack.json: not available — Only meaningful in a directive.
- CLI: not available — Only meaningful in a directive.
- env: not available — Only meaningful in a directive.
- directive: `/* @afterpack skip */`

## Scope and preservation

Files, names and runtime patterns AfterPack must leave alone.

### paths.include

Globs that re-admit what the CLI's directory walk skips. Nested `node_modules/` is skipped by default; `**/node_modules/**` walks it and takes every `.js`/`.mjs`/`.cjs` inside. It only ever adds files, and `paths.exclude` still wins over it.

- Type: `glob[]`
- Default: `[]`
- Tier: Free
- Scope: program
- Note: A walk-only key: it does nothing in a bundled build, where the bundler has already inlined your dependencies into the chunks and no `node_modules` path is left to match. Same glob grammar as `paths.exclude`, which means an unanchored pattern is tried at every path segment, so any non-empty value lets the walk descend into `node_modules/` and `["src/**"]` matches dependency files under `node_modules/*/src/` too. Lead with `/` to anchor a pattern to one absolute location. Quote the glob on a command line or the shell expands it first.
- afterpack.json: `{ "paths": { "include": ["**/node_modules/**"] } }`
- CLI: `npx afterpack@latest dist/ --paths.include=**/node_modules/**`
- env: `AFTERPACK_paths_include=**/node_modules/**`
- directive: not available — Applies to the whole program; cannot be set per region.

### paths.exclude

Files to leave untouched, as globs. A matching file is copied to the output unchanged. Applies to files, not to code a bundler has already merged into your bundle.

- Type: `glob[]`
- Default: `[]`
- Tier: Free
- Scope: program
- afterpack.json: `{ "paths": { "exclude": ["**/*.min.js", "dist/vendor/**"] } }`
- CLI: `npx afterpack@latest dist/ --paths.exclude=**/*.min.js,dist/vendor/**`
- env: `AFTERPACK_paths_exclude=**/*.min.js,dist/vendor/**`
- directive: not available — Applies to the whole program; cannot be set per region.

### identifiers.rename

Renames identifiers. `false` keeps every name and is meant for debugging; use `identifiers.reserved` to keep specific names. Exported and reflected names are never renamed.

- Type: `boolean`
- Default: `true`
- Tier: Free
- Scope: program
- afterpack.json: `{ "identifiers": { "rename": false } }`
- CLI: `npx afterpack@latest dist/ --identifiers.rename=false`
- env: `AFTERPACK_identifiers_rename=false`
- directive: not available — Applies to the whole program; cannot be set per region.

### identifiers.globals.rename

Also renames the top-level names of a classic script. Safe only for a script nothing else calls into, in a single-file build.

- Type: `boolean`
- Default: `false`
- Tier: Free
- Scope: program
- afterpack.json: `{ "identifiers": { "globals": { "rename": true } } }`
- CLI: `npx afterpack@latest dist/ --identifiers.globals.rename`
- env: `AFTERPACK_identifiers_globals_rename=true`
- directive: not available — Applies to the whole program; cannot be set per region.

### identifiers.methods.rename

Obfuscates class method names, including what `Function.prototype.name` returns. `false` keeps them, for code that reads `fn.name`, such as a dependency-injection container or a serializer.

- Type: `boolean`
- Default: `true`
- Tier: Free
- Scope: program
- afterpack.json: `{ "identifiers": { "methods": { "rename": false } } }`
- CLI: `npx afterpack@latest dist/ --identifiers.methods.rename=false`
- env: `AFTERPACK_identifiers_methods_rename=false`
- directive: not available — Applies to the whole program; cannot be set per region.

### identifiers.reserved

Identifier names that are never renamed. A plain name applies to the whole build. Use it for names other code expects, such as a bundled library's public API.

- Type: `(string | { glob: string, names: string[] })[]`
- Default: `[]`
- Tier: Free
- Scope: program
- Note: An item can also be `{ "glob": "src/legacy/**", "names": ["jQuery"] }`, which applies only inside matching files. That form is `afterpack.json` and plugin options only; a flag or a variable carries plain names.
- afterpack.json: `{ "identifiers": { "reserved": ["Hls", "gtag"] } }`
- CLI: `npx afterpack@latest dist/ --identifiers.reserved=Hls,gtag`
- env: `AFTERPACK_identifiers_reserved=Hls,gtag`
- directive: not available — Applies to the whole program; cannot be set per region.

### reflection.allow

Runtime reflection patterns your code relies on. AfterPack fails the build when it detects a pattern you have not listed. `angular` and `nestjs` expand to the patterns those frameworks need.

- Type: `enum[]`
- Default: `[]`
- Tier: Free
- Scope: program
- Values: `functionToString`, `nameIntrospection`, `argumentsCallee`, `prototypeChain`, `decoratorMetadata`, `constructorIntrospection`, `angular`, `nestjs`
- afterpack.json: `{ "reflection": { "allow": ["functionToString"] } }`
- CLI: `npx afterpack@latest dist/ --reflection.allow=functionToString`
- env: `AFTERPACK_reflection_allow=functionToString`
- directive: not available — Applies to the whole program; cannot be set per region.

## Output

Files a build writes next to your code.

### sourceMap.enabled

Writes a source map next to the output. A published map reverses the obfuscation. Never deploy it.

- Type: `boolean`
- Default: `true in development when an input map exists; false in production`
- Tier: Free
- Scope: program
- afterpack.json: `{ "sourceMap": { "enabled": false } }`
- CLI: `npx afterpack@latest dist/ --sourceMap.enabled=false`
- env: `AFTERPACK_sourceMap_enabled=false`
- directive: not available — Applies to the whole program; cannot be set per region.

### sourceMap.sourcesContent

Embeds your original source in the map. Never publish a map with this on.

- Type: `boolean`
- Default: `true in development; false in production`
- Tier: Free
- Scope: program
- afterpack.json: `{ "sourceMap": { "sourcesContent": false } }`
- CLI: `npx afterpack@latest dist/ --sourceMap.sourcesContent=false`
- env: `AFTERPACK_sourceMap_sourcesContent=false`
- directive: not available — Applies to the whole program; cannot be set per region.

### sourceMap.emitUrl

Appends the `//# sourceMappingURL=` comment to the output. The map file is written regardless.

- Type: `boolean`
- Default: `true in development; false in production`
- Tier: Free
- Scope: program
- afterpack.json: `{ "sourceMap": { "emitUrl": false } }`
- CLI: `npx afterpack@latest dist/ --sourceMap.emitUrl=false`
- env: `AFTERPACK_sourceMap_emitUrl=false`
- directive: not available — Applies to the whole program; cannot be set per region.

### protectionMap.enabled

Writes the Protection Map, an HTML report of what was applied to each part of your source, into `.afterpack/`. The report contains your full source. Never publish it.

- Type: `boolean`
- Default: `true when the bundler emitted a source map`
- Tier: Free
- Scope: program
- afterpack.json: `{ "protectionMap": { "enabled": false } }`
- CLI: `npx afterpack@latest dist/ --protectionMap.enabled=false`
- env: `AFTERPACK_protectionMap_enabled=false`
- directive: not available — Applies to the whole program; cannot be set per region.

### protectionMap.detailed

Lists, for every region of the Protection Map, the transformations applied to it. `false` makes the report smaller.

- Type: `boolean`
- Default: `true`
- Tier: Free
- Scope: program
- afterpack.json: `{ "protectionMap": { "detailed": false } }`
- CLI: `npx afterpack@latest dist/ --protectionMap.detailed=false`
- env: `AFTERPACK_protectionMap_detailed=false`
- directive: not available — Applies to the whole program; cannot be set per region.

## Build

How a build runs.

### seed

The random seed for the build. Unset, every build gets a new seed and different output. Set a number, any string, or `"git"` for the current commit to reproduce a build.

- Type: `number | string | "git"`
- Default: `a new random seed per build`
- Tier: Free
- Scope: program
- afterpack.json: `{ "seed": "git" }`
- CLI: `npx afterpack@latest dist/ --seed=git`
- env: `AFTERPACK_seed=git`
- directive: not available — Applies to the whole program; cannot be set per region.

### build.mode

Selects production or development defaults for output settings such as source maps and backups.

- Type: `enum`
- Default: `detected from the environment`
- Tier: Free
- Scope: program
- Values: `production`, `development`
- afterpack.json: `{ "build": { "mode": "production" } }`
- CLI: `npx afterpack@latest dist/ --build.mode=production`
- env: `AFTERPACK_build_mode=production`
- directive: not available — Applies to the whole program; cannot be set per region.

### build.autorun

Runs AfterPack automatically at the end of your bundler's build. With `false` the plugin only reads directives, and you run the engine yourself.

- Type: `boolean`
- Default: `true`
- Tier: Free
- Scope: program
- afterpack.json: `{ "build": { "autorun": false } }`
- CLI: `npx afterpack@latest dist/ --build.autorun=false`
- env: `AFTERPACK_build_autorun=false`
- directive: not available — Applies to the whole program; cannot be set per region.

### build.backup

Keeps a verbatim copy of every original file, so a run can be undone. The CLI writes a backup DIRECTORY, `.afterpack/backup/` at your project root, with a `manifest.json` recording what each file became, and `afterpack restore` puts the originals back; it is on there by default. A framework plugin writes a `.backup.<hash>` sibling beside each output file instead, and only when you set this to `true`.

- Type: `boolean`
- Default: `false for an in-place pass; the CLI's own backup directory is on by default`
- Tier: Free
- Scope: program
- Note: Either form is your source verbatim. The plugin's sibling lands inside the tree you deploy; the CLI's directory sits outside it, gitignored. Never deploy either.
- afterpack.json: `{ "build": { "backup": true } }`
- CLI: `npx afterpack@latest dist/ --build.backup`
- env: `AFTERPACK_build_backup=true`
- directive: not available — Applies to the whole program; cannot be set per region.

### directives.enabled

Reads `@afterpack` comments in your source and applies them as region overrides.

- Type: `boolean`
- Default: `true`
- Tier: Free
- Scope: program
- afterpack.json: `{ "directives": { "enabled": false } }`
- CLI: `npx afterpack@latest dist/ --directives.enabled=false`
- env: `AFTERPACK_directives_enabled=false`
- directive: not available — Applies to the whole program; cannot be set per region.

### diagnostics.level

How much a build prints. `summary` prints errors in full and counts the rest. `all` prints everything. `none` silences the progress and summary lines; errors still print.

- Type: `enum`
- Default: `summary`
- Tier: Free
- Scope: program
- Values: `summary`, `all`, `none`
- afterpack.json: `{ "diagnostics": { "level": "all" } }`
- CLI: `npx afterpack@latest dist/ --diagnostics.level=all`
- env: `AFTERPACK_diagnostics_level=all`
- directive: not available — Applies to the whole program; cannot be set per region.

### diagnostics.format

Switches the CLI's own output between human-readable text and one JSON document on stdout, with every human-readable line moved to stderr. This is the shape a CI step or an AI agent should read.

- Type: `enum`
- Default: `text`
- Tier: Free
- Scope: program
- Values: `text`, `json`
- Note: CLI only; a plugin build accepts and ignores it, since a bundler owns its own build output, not stdout.
- afterpack.json: `{ "diagnostics": { "format": "json" } }`
- CLI: `npx afterpack@latest dist/ --diagnostics.format=json`
- env: `AFTERPACK_diagnostics_format=json`
- directive: not available — Applies to the whole program; cannot be set per region.

### allowUnobfuscated

Ships a file the engine could not obfuscate as cleartext instead of failing the build. The run still exits `2` so a script can detect it. Off by default: AfterPack fails closed, and turning this on ships less protection than you asked for on the affected file.

- Type: `boolean`
- Default: `false`
- Tier: Free
- Scope: program
- afterpack.json: `{ "allowUnobfuscated": true }`
- CLI: `npx afterpack@latest dist/ --allowUnobfuscated`
- env: `AFTERPACK_allowUnobfuscated=true`
- directive: not available — Applies to the whole program; cannot be set per region.

### telemetry.enabled

Sends an anonymous report when a build reports an error-level diagnostic (a refused or partial build): the diagnostic code, byte offsets, and the tool, OS and architecture versions. Never source, paths or file names. A clean build sends nothing.

- Type: `boolean`
- Default: `true`
- Tier: Free
- Scope: program
- afterpack.json: `{ "telemetry": { "enabled": false } }`
- CLI: `npx afterpack@latest dist/ --telemetry.enabled=false`
- env: `AFTERPACK_telemetry_enabled=false`
- directive: not available — Applies to the whole program; cannot be set per region.

### key

Your Pro API key. With a key, builds run on the Pro engine. Set it through the environment or a CI secret rather than a committed file.

- Type: `string`
- Default: `unset; builds run locally on the Free engine`
- Tier: Pro
- Scope: program
- afterpack.json: `{ "key": "ap_v1_…" }`
- CLI: `npx afterpack@latest dist/ --key=ap_v1_…`
- env: `AFTERPACK_key=ap_v1_…`
- directive: not available — Applies to the whole program; cannot be set per region.

## Example afterpack.json

```json
{
  "preset": "hard",
  "strings": { "minLength": 4 },
  "identifiers": { "reserved": ["Hls"] },
  "paths": { "exclude": ["**/*.min.js", "dist/vendor/**"] },
  "protectionMap": { "enabled": true }
}
```

## Next

- [Presets](https://www.afterpack.dev/docs/presets): what each preset sets.
- [Complexity](https://www.afterpack.dev/docs/complexity): what rises with the number, and which transformations config can turn off.
- [Directives](https://www.afterpack.dev/docs/directives): protecting one region of your source differently.
- [Protection Map](https://www.afterpack.dev/docs/protection-map): checking what a build applied.
