This page is available in English only.

JavaScript obfuscation FAQ

The most-asked questions about AfterPack, answered in a few short paragraphs each.

General questions — what AfterPack is, whether it's free, whether it breaks your app — are answered on the landing FAQ. This page is the build-level detail.

What's the difference between Free and Pro?

Free runs the full pipeline uniformly across the whole bundle. Pro adds aim: you mark a region and only that code gets the heavy treatment. Tiers has the full matrix and the prices.

Do I need the framework plugin?

For a first-class framework, yes. Install the plugin as a dev dependency and add one config line, and your normal build emits obfuscated output. Where the engine runs depends on the bundler: Vite, Rollup, webpack and Parcel obfuscate inside the bundler's own pipeline, Next.js obfuscates from a hook inside next build, and esbuild and Angular run a pass once their build has written.

$ npm install -D @afterpack/vite

For pure-bundler or zero-plugin stacks, point the CLI at your build output instead:

$ npx afterpack@latest dist/

Either way, AfterPack runs strictly post-build, on your built output. The build directory is required; there is no auto-detection. The CLI is also the path for CI and manual one-off runs on plugin-supported frameworks.

Why does the same code produce different output each build?

That's per-build polymorphism, and it's the primary defense. With the default random seed, two builds of the same input come out structurally different. A static deobfuscator that learns the shape of build N gets nothing reusable for build N+1, so rebuilding production periodically keeps resetting an attacker's progress.

When you need identical bytes, for CI cache hits or golden-snapshot tests, pin the seed with --seed:

$ npx afterpack@latest dist/ --seed=git

The release model: dev builds are un-obfuscated for fast iteration; production builds the obfuscated artifact once and promotes the same bytes through qa, preprod, and prod. See Builds & CI.

Is Free just renaming?

No. Renaming is the floor. The Free baseline flattens control flow, fuses and inflates logic, decomposes expressions, reuses fragments, and materializes constants, all within a file. The output is restructured, not relabeled — it already reaches the polynomial-non-injective reversal class, where the original structure isn't uniquely recoverable from the output.

Does a directive only affect one line?

No. A directive scopes a whole region, not just its own line. Open a block with /* @afterpack preset=hard */ alone on the line above a function and close it with /* @afterpack end */ after the closing brace, and it covers the whole function, body included:

/* @afterpack preset=hard */
export function checkLicense(token: string) {
  // the entire function body is covered
}
/* @afterpack end */

That's the block form: an opener alone on its line, closed by a matching /* @afterpack end */. For a single value, an inline /* @afterpack preset=extreme */ covers the rest of its line, the literal or expression right after it. See Directives for the full grammar.

What happens if the Pro cloud is down?

It retries with backoff, then fails closed: a cloud outage breaks CI rather than shipping less protection than you asked for.

If you need no third-party dependency in the build path at all, run Free locally — it never makes a network call. See Deployment modes.

How do source maps work?

AfterPack's source maps chain obfuscated output back to your original source. They are useful for local debugging. Never ship one to production: a public .map hands an attacker a path straight to the source you just obfuscated.

AfterPack keeps them out of your production bundle by default: source-map emission is off on a production build, and the //# sourceMappingURL= comment is dropped too. See Best practices.

Can I use AfterPack in CI?

Yes. For a first-class framework, the plugin runs as part of your normal build, so your existing build step already emits obfuscated output. For other stacks, add npx afterpack@latest <path> as a post-build step.

Pin the seed to your release identifier for reproducible artifacts, build the obfuscated output once, and promote the same bytes through your environments. Audit each release and attach the Protection Map as a CI artifact. See Builds & CI for a full pipeline example.

Does obfuscation slow my code down?

Modestly. Restructuring control flow and reconstructing constants adds runtime work, but on a typical web app the cost is usually small relative to network and rendering time.

The bigger the preset, the more it costs: each rung maps to a higher complexity, and the default is light. Raise the global preset when a project needs more protection, and reserve extreme for the regions where you've chosen latency in exchange for protection. The ladder and its values are on Presets.

How do I protect API keys and license logic?

Mark them. Use an inline /* @afterpack preset=extreme */ on a secret literal, and wrap the function that gates licensing in a /* @afterpack preset=hard *//* @afterpack end */ block:

const LICENSE_SECRET = /* @afterpack preset=extreme */ "YOUR_SECRET";

/* @afterpack preset=hard */
export function checkLicense(token: string) {
  /* ... */
}
/* @afterpack end */

preset=extreme raises that region to complexity target 80 with the string floor forced on, so the literal is encoded rather than shipped in cleartext. It still exists in the output, and the program reconstructs it at use. To keep a literal your code compares against out of the output entirely, turn on transforms.comparisonHardening.enabled: the comparison becomes a one-way digest check and only the digest ships. Either way, an attacker who runs the code under an instrumented runtime can still reach the value (see the next question). These directives raise the cost of static recovery on every release. They do not turn a high-value secret into something safe to keep client-side. See Best practices for the full pattern.

Can someone who runs my code extract a secret?

Yes. A determined attacker who runs your code under an instrumented runtime can reach any secret the code itself uses. No build-time obfuscator changes that: if the running program needs the value to do its job, it's observable to someone who patches the runtime, hooks the right call, or snapshots the heap at the right moment.

AfterPack makes the value invisible to the cheaper attacks: the static reader and the blind LLM that explains code without running it. Non-materialization keeps a gated literal out of the artifact entirely, the string floor keeps the rest out of cleartext, and per-build polymorphism means the work to re-extract anything has to be redone from scratch every release.

Obfuscation raises the static and re-extraction cost of a client-side secret. The only way to keep a high-value secret out of an attacker's reach is to never ship it to the client: keep it server-side and have the server make the decision. Use preset=extreme for the secrets that genuinely can't move server-side, and treat it as raising cost, never as a vault.

What frameworks are supported?

These stacks have a published plugin: Next.js, Vite, Webpack, Rollup, esbuild, Astro, Svelte, SvelteKit, Vue 3, Nuxt 3, Angular v17+, Electron and Parcel. A plugin knows its own output directory, so there is nothing to point it at.

Remix and plain JS run through the CLI post-build, where you name the directory yourself (npx afterpack@latest dist/; Next.js writes to .next/, Nuxt to .output/). See Frameworks for the full matrix and per-stack setup, and the public Security Scanner if you want to see what protection looks like on a real bundle.

Where do I ask a question, report a bug or propose a feature?

On GitHub. Questions and proposals go to GitHub Discussions; bugs go to GitHub Issues. A security issue goes to security@afterpack.dev instead of a public thread, see SLAs, SLOs & support.

Next

  • Quickstart: install, build, ship in a few minutes
  • Tiers: Free vs Pro, feature by feature
  • Config: every option, and which form can set it
  • Directives: the @afterpack grammar and which keys apply
  • Presets: the five-rung ladder
  • Best practices: secrets, source maps, and CI