# 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.

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

A preset is a named level of protection. One name sets three settings together: the [complexity target](https://www.afterpack.dev/docs/config#complexity), the output size multiplier, and the [inflation budget](https://www.afterpack.dev/docs/config#inflation-max). Setting [`complexity`](https://www.afterpack.dev/docs/config#complexity) explicitly changes only the target; the other two stay as the preset defines them.

*(preset ladder diagram — see https://www.afterpack.dev/docs/presets)*

## The ladder

| Preset | [`complexity`](https://www.afterpack.dev/docs/config#complexity) | Max output size | [String floor](https://www.afterpack.dev/docs/config#strings-encode) | Reach for it when |
|---|---:|---:|:---:|---|
| `minify` | `0` | `1.2x` | off | Size reduction only. No obfuscation; string literals stay readable. |
| `light` | `2` | `2.0x` | on | **Default.** String literals are encoded, structure lightly inflated. The right baseline for most projects. |
| `medium` | `8` | `2.5x` | on | Production code you want meaningfully harder to follow, at a modest size cost. |
| `hard` | `25` | `4.0x` | on | Code that matters: pricing, gating, license checks, client-side business logic. |
| `extreme` | `80` | `7.0x` | on | The highest applied complexity. Aim it at a file or [region](https://www.afterpack.dev/docs/directives#what-you-can-set) rather than a whole bundle. |

The string floor is on for any positive target.

## The default is `light`

Run [`npx afterpack@latest dist/`](https://www.afterpack.dev/docs/cli#usage) with no [`--preset`](https://www.afterpack.dev/docs/config#preset), or install a [plugin](https://www.afterpack.dev/docs/frameworks) and configure nothing, and you get `light`.

```bash
npx afterpack@latest dist/
```

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

[Flags](https://www.afterpack.dev/docs/config) 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](https://www.afterpack.dev/docs/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`](https://www.afterpack.dev/docs/config#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`](https://www.afterpack.dev/docs/diagnostics#complete-reference). 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`](https://www.afterpack.dev/docs/diagnostics#complete-reference), no output, [exit `1`](https://www.afterpack.dev/docs/diagnostics#exit-codes). 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`](https://www.afterpack.dev/docs/config#complexity) is an unbounded non-negative number. [`--complexity=200`](https://www.afterpack.dev/docs/config#complexity) is a valid [Free-tier](https://www.afterpack.dev/docs/tiers) override, well past what `extreme` sets.

```bash
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`](https://www.afterpack.dev/docs/config#complexity) is an error.

## Applying a preset to one region

`--preset` sets the whole bundle uniformly; that is [Free](https://www.afterpack.dev/docs/tiers). Concentrating a heavier preset on one function or file is a [Pro](https://www.afterpack.dev/docs/pro#what-pro-buys) feature, through a [source directive](https://www.afterpack.dev/docs/directives):

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

Directives are [block comments only](https://www.afterpack.dev/docs/directives#writing-one), read from your source by the plugin. See [Directives](https://www.afterpack.dev/docs/directives) for the grammar and the tier rules.

## Next

- [Configuration](https://www.afterpack.dev/docs/config): every key a preset touches.
- [CLI reference](https://www.afterpack.dev/docs/cli): the flags that select a preset.
- [Directives](https://www.afterpack.dev/docs/directives): [`skip`](https://www.afterpack.dev/docs/config#skip) or [`preset=<name>`](https://www.afterpack.dev/docs/config#preset) for one span.
- [How AfterPack works](https://www.afterpack.dev/docs/concepts): what a higher target actually buys against a static reader.
- [Best practices](https://www.afterpack.dev/docs/best-practices): what to push harder and what to leave alone.
