cd /news/developer-tools/announcing-afterpack-a-free-javascri… · home › topics › developer-tools › article
[ARTICLE · art-144218] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Announcing AfterPack: a free JavaScript obfuscator for the web

A developer launched AfterPack, a free JavaScript obfuscator that reseeds every build so identifiers, encoded strings, decoder signatures and masked constants all change, aiming to break scripts written against a previous release. The developer reports that in a September 2026 measurement (six seeds × five samples), under 6% of what a deobfuscator recovered from one build still resolved on the next, and cites a May 2026 test in which Claude Opus 4.6 and 4.7 recovered clean source from two popular obfuscators' flagship demos in 10 and 20 minutes. The tool ships as a CLI, bundler plugins and a WebAssembly build for Cloudflare Workers, with Pro cloud builds starting at $49 a month.

by read9 min views1 publishedOct 3, 2026

I built AfterPack; this is the launch post from our blog.

Today we're launching three things:

AfterPack (afterpack.dev), the JavaScript obfuscator, works with any framework. The CLI and plugins are open source, the local engine is free, and Pro cloud builds start at $49 a month. Start with npx afterpack@latest after a build, or ask your coding agent to add it.

Meet AfterPack: a free build tool that makes shipped code unreadable to scanners and people, and a moving target for AI. Every build ships completely different code, so a script written to patch one release — a cheat, a userscript, a bypass — doesn't fit the next. A tool written against your code should stop working at your next release, and now, inside your own Cloudflare Worker, it can stop working at your very next request.

Because whatever AI can read, it can also rewrite and repackage. Point a coding agent at your bundle, and a few minutes later someone holds your pricing rules, your paywall check or your anti-bot logic as clean, editable source, along with a script that patches or bypasses them. That used to be a specialist's job; now it's a prompt. And the patch keeps working for as long as your code keeps its shape. Minification was never hiding that code: the Claude Code "leak" was a readable bundle that had been sitting on npm since launch. What a minified bundle still gives away, and how to check your own site, is covered in what users can see in your JavaScript and how to protect it.

In May 2026, I gave two popular obfuscators' own flagship demos to Claude Code with one four-paragraph prompt. Claude Opus 4.6 came back with clean source in 10 minutes, Claude Opus 4.7 in 20. They were small demos, not whole apps, and those models are already a generation behind today's.

Your pricing rules, license checks, anti-fraud heuristics and unreleased features have always been in the bundle. What changed is who can read them, and how fast. What you still control is how much of that work carries over to your next release.

Yes. Given enough time, any obfuscator's output can be reversed, AfterPack's included. What AfterPack changes is carry-over: how much of the work to reverse one release still applies to the next. In our own measurement (September 2026, six seeds × five samples), under 6% of what a deobfuscator recovered from one build still resolved on the next (how we measured).

Logic someone has already read also stays read: if they worked out your discount rule once, a new build won't make them forget it.

What can expire is the tool built on that read. A script that strips a license check, a patcher for a paywall, an extractor that pulls your scoring rules out of every release: each is written against the structure of one build. The most popular open-source obfuscator emits fixed output shapes, and free public deobfuscators ship hardcoded recognizers for them, so a tool written once keeps working on every future build.

AfterPack starts from a new random seed on every build. Identifier names, encoded strings, the decoder's signature, state numbering and masked constants all come out different, so the details a tool hard-codes change every time. Run the engine inside a Worker and the window shrinks from a release to a single request.

A CLI, plugins for the bundlers you already use, a WebAssembly build for Workers, Pro cloud builds, a report of what each build protected, and a free site scanner.

Fact AfterPack
What it is A JavaScript obfuscator for production builds: it rewrites what your bundler produces, not your source files
Engine Rust, run locally by the CLI and the plugins, or as WebAssembly ( @afterpack/wasm ) inside your own Worker
Output Different on every build by default in the CLI and the plugins; pin a seed only when you need identical bytes
License CLI and plugins Apache-2.0; the engine is free to use under the AfterPack Engine License
Price Local engine free; Pro from $49 a month ( plans )
Start npx afterpack@latest after your build, or aframework plugin

What the table doesn't show:

npx afterpack audit <url>. Identifiers vanish and string literals are encoded behind a runtime decoder; how much more happens depends on the preset. light (the default) encodes strings and rewrites syntax, adding no structural layers — the right baseline for most projects. medium makes production code meaningfully harder to follow; hard is for code that matters, like pricing, gating and license checks; extreme sets the highest complexity of the presets, best aimed at one function or file rather than a whole bundle.

A 139-byte function, before:

export function discount(plan, seats) {
  if (plan === "team" && seats >= 10) return 0.2;
  if (plan === "team") return 0.1;
  return 0;
}

And after one npx afterpack@latest run at the default light preset (27 September 2026):

export function discount(N, O) {
  if (N === Jr("T|P4") && O >= 10) return 0.2;
  if (N === Jr("T|P4")) return 0.1;
  return 0;
}

"team" is gone, replaced by a ciphertext and a decoder call; run it again and the names, the ciphertext and the decoder's signature all come out different. At light, numbers such as 10, 0.2 and 0.1 stay readable; medium and up also mask integer constants like that 10. There's overhead for the decoder that ships alongside the encoded strings, so a file this small comes out proportionally larger than a real bundle would: on a real bundle, light runs 1.9 to 2.4 times the input, gzipped (presets).

Paste your own function into the playground to see what each preset does to it — no install, no account.

Add AfterPack to this project: read afterpack.dev/llms.txt, follow the quickstart for my framework, then run a production build and show me the Protection Map. npx afterpack@latest after your next build. @afterpack/wasm runs the engine as WebAssembly inside your own Worker, so a fresh seed on every call obfuscates each response differently:

import { obfuscate } from "@afterpack/wasm";

export default {
  async fetch(request) {
    const upstream = await fetch("https://example.com/app.js"); // your origin's bundle
    if (!upstream.ok) return upstream;
    const source = await upstream.text();
    const result = await obfuscate(
      { path: "app.js", source },
      { preset: "hard", seed: crypto.randomUUID() },
    );
    return new Response(result.bytes, {
      headers: { "content-type": "application/javascript" },
    });
  },
};

If we run that handler in Node on an Apple M2 Max (27 September 2026), serving the discount file from a local origin, four requests come back as four different outputs, each returning the right discounts. Once the module is warm, each obfuscation takes under 4 ms; the first call, which instantiates the engine, takes about 40 ms. That's a 139-byte input; a real bundle costs far more CPU, and it's paid on every response. The Workers guide covers the plan limits and when caching one shape per rotation window is the better trade.

The full setup, with wrangler config, one cached shape per time window and real curl output, is in the tutorial on how to obfuscate JavaScript on every request with Cloudflare Workers.

Run the CLI after your build, or install the plugin for your bundler so every production build comes out obfuscated. The CLI needs no setup; run this in the project root after building:

npx afterpack@latest

It finds your build output (dist/, .next/, .output/, build/ or out/), rewrites it in place and keeps a backup; npx afterpack@latest restore undoes the run.

To make obfuscation part of the build itself, install the plugin for your bundler:

npm install -D @afterpack/next   # or @afterpack/vite, @afterpack/webpack

Each plugin takes one small config change, such as wrapping your Next.js config in withAfterpack(config); frameworks shows it for every supported bundler, from Astro to Parcel. To see what your live site exposes today, run it through the scanner first.

AfterPack raises the cost of reading your code and of reusing tooling against it; it cannot hide values from someone who instruments the running program, so secrets and anything that grants access belong on your server. What it does give you comes with the build you already run: a new target every release, with no extra step to remember.

Next is network obfuscation: network transport cloaking will run your API requests and responses through a codec that changes with every build. Cross-module obfuscation will tie logic together across module boundaries, and AfterPack on Workers for Platforms will serve a new shape per request with nothing to install. Past JavaScript, we're heading for HTML and CSS.

Yes. The CLI, the framework plugins and the local engine are free, and your source never leaves your machine. Pro adds cloud builds and per-region directives from $49 a month, and a registered Free workspace gets 10 MB of Pro builds a month. The full table is on plans and tiers.

The CLI and the framework plugins are, under Apache-2.0, on GitHub. The engine they run is free to use under the AfterPack Engine License.

Modestly, and more at stronger presets. The default is light. Raise the preset for a whole project, or use a Pro directive to aim hard or extreme at only the functions that need it.

It works on your production build through a plugin for the bundler you already use, and by default every build produces different output, so a deobfuscator written for one release mostly stops working on the next. Build time, output size and carry-over, measured side by side with other obfuscators, are on the comparison page.

No. Anything your running code uses can be observed by someone who runs it in a browser they control, so keep API keys and other secrets on your server. Encoding does keep a key out of a grep and out of automated secret scanners, which buys time to rotate one that shipped by accident (best practices).

Found a bug, or want a bundler we don't cover yet? Open an issue on GitHub with your bundler and its version; that's where I read feedback.

The code you ship has always been readable. From today, what someone learns from one release no longer has to carry over to the next.

— Nikita

── more in #developer-tools 4 stories · sorted by recency
── more on @afterpack 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/announcing-afterpack…] indexed:0 read:9min 2026-10-03 · —