This page is available in English only.

Obfuscation presets

The five protection levels from minify to extreme, the three engine parameters each one sets together, and what the zero-config default (light) already guarantees.

A preset is a named level of protection. One name sets three settings together: the complexity target, the output size multiplier, and the inflation budget. Setting complexity explicitly changes only the target; the other two stay as the preset defines them.

The five obfuscation presets ranked by complexity target and total output multiplier, with light marked as the defaultextremetarget 807x max output sizehardtarget 254x max output sizemediumtarget 82.5x max output sizelighttarget 2DEFAULT2x max output sizeminifytarget 01.2x max output sizeZero config gives you light: no readable string survives, at 2x size. Step up per project.

The ladder

PresetcomplexityMax output sizeString floorReach for it when
minify01.2xoffSize reduction only. No obfuscation; string literals stay readable.
light22.0xonDefault. String literals are encoded, structure lightly inflated. The right baseline for most projects.
medium82.5xonProduction code you want meaningfully harder to follow, at a modest size cost.
hard254.0xonCode that matters: pricing, gating, license checks, client-side business logic.
extreme807.0xonThe highest applied complexity. Aim it at a file or region rather than a whole bundle.

The string floor is on for any positive target.

The default is light

Run npx afterpack@latest dist/ with no --preset, or install a plugin and configure nothing, and you get light.

$ npx afterpack@latest dist/
npx afterpack@latest dist/ --preset=hard    # step up

Flags join their value with =. A space-separated value is rejected as an unknown flag.

light is the zero-config floor. Every string literal it can rewrite goes through a runtime decoder. Some strings stay readable at every preset: directive prologues, typeof comparands, property names the runtime needs, and export names. The Protection Map lists them, and the engine reports the count and byte total on every build. Raising the preset from light to hard adds structural work: more inflation, more entanglement, more control-flow reshaping. It does not change string readability, which is already at its floor.

minify is the one rung that turns the floor off. It is minification only, with no obfuscation applied.

Size budget

A preset carries its own inflation.max rung: the multiplier column above. An unset inflation.max resolves to that rung.

The multiplier is a budget for a build, not a promise about one small file. Every output carries the engine's fixed runtime overhead — the decoders and the integer-expression interpreter — so a file of a few hundred bytes comes out several times larger than the rung suggests. Aim the multiplier at bundles, and read the ratio on a real one.

The two behave differently when the budget is reached:

  • Preset budget (unset inflation.max): the build stops adding transformations when the budget is reached and reports DIAG_INFLATION_BUDGET_HIT. The output is valid, with fewer transformations than the target asked for. The build succeeds.
  • Explicit inflation.max: hitting it is an error: DIAG_SIZE_CAP_REACHED, no output, exit 1. Under-protected output is never written in its place.

Set inflation.max yourself only when you have a real size budget you would rather fail than exceed.

Setting the target directly

complexity is an unbounded non-negative number. --complexity=200 is a valid Free-tier override, well past what extreme sets.

npx afterpack@latest dist/ --preset=hard --complexity=40

That is hard's size limits at target 40: the preset's multiplier and budget stay, only the target moves. Passing a preset name to --complexity is an error.

Applying a preset to one region

--preset sets the whole bundle uniformly; that is Free. Concentrating a heavier preset on one function or file is a Pro feature, through a source directive:

/* @afterpack preset=extreme */
function pricingEngine(plan, region) {
  return resolve(plan, region);
}
/* @afterpack end */

Directives are block comments only, read from your source by the plugin. See Directives for the grammar and the tier rules.

Next