A 100-Megabyte Binary for a CLI
Anthropic just announced that Claude Code is now available as a native build. Translation: a binary executable you can install with a curl command that doesn’t need Node.js.
Sounds good, right? One command, no dependencies, background auto-updates. Any CLI tool’s dream.
But there’s a catch: the binary weighs 100MB.
To put this in perspective, the git binary weighs about 3MB. curl is less than 1MB. Even Go, which has a reputation for generating fat binaries, rarely exceeds 15-20MB.
What the hell is inside those 100 megs?
It’s Not Rust, It’s Bun in an Executable Suit
When I saw the announcement, my first thought was: “They’ve rewritten everything in Rust.” Makes sense, right? If you want a native binary that’s fast and runtime-free, Rust is the obvious choice.
Well, turns out that’s not the case.
Claude Code is still TypeScript. What they’ve done is use bun build --compile to package it as an executable.
How bun build --compile Works
The magic command is this:
| |
What exactly does it do? Three things:
1. Bundling
First, Bun acts as a bundler. It takes your entry file (index.ts), resolves all the import statements, and generates a single JavaScript file with all the code concatenated. It includes your dependencies from node_modules, applies tree-shaking to eliminate dead code, and minifies the result.
So far, nothing different from what esbuild or webpack does.
2. Embedding
Here’s where it gets interesting. Bun takes that JavaScript bundle and embeds it inside an executable along with the complete Bun runtime.
The resulting executable has this structure (simplified):
┌─────────────────────────────────┐
│ Bun Runtime (~95MB) │
│ ├── JavaScriptCore engine │
│ ├── Native APIs (fs, http) │
│ ├── Zig runtime │
│ └── Static libc │
├─────────────────────────────────┤
│ Your bundled code (~5MB) │
│ └── Minified JavaScript │
└─────────────────────────────────┘
When you run the binary, the Bun runtime extracts the JavaScript code from itself and executes it. It’s like a self-extracting ZIP file, but for code.
3. Cross-compilation
Bun can generate binaries for other platforms:
| |
You don’t need to have Linux to generate a Linux binary. Bun includes precompiled runtimes for each platform.
JavaScriptCore vs V8
Node.js uses V8, Chrome’s JavaScript engine. Bun uses JavaScriptCore (JSC), Safari’s engine.
Why does it matter? Because they’re different beasts:
| Aspect | V8 (Node) | JavaScriptCore (Bun) |
|---|---|---|
| Startup time | ~50ms | ~5ms |
| Peak performance | Very high | High |
| Memory usage | Higher | Lower |
| JIT tiers | 2 (Ignition → TurboFan) | 4 (LLInt → Baseline → DFG → FTL) |
JSC has faster startup because it has more JIT compilation tiers. It starts interpreting code very quickly (LLInt) and optimizes in the background while executing. V8, on the other hand, needs to do more initial work before it starts executing.
For a CLI that starts up, does something, and terminates, those 45ms difference in startup matter. For a server that runs for hours, it matters less.
Why Zig (and Not Rust, nor C++)
Bun is written primarily in Zig, with some C++ for the parts that interact with JavaScriptCore.
Jarred Sumner, Bun’s creator, chose Zig for several reasons:
C interoperability: Zig can call C code with no overhead or FFI. JavaScriptCore is written in C++, and Zig can link with it directly.
Memory control without garbage collection: Like Rust, but with simpler syntax and without the borrow checker that makes you want to pull your hair out.
Trivial cross-compilation: Zig can compile for any platform from any platform. You don’t need a Linux machine to compile for Linux.
Small binaries (relatively): A “Hello World” in Zig weighs ~5KB. In Go, ~2MB. In Rust, ~300KB.
The result is a runtime that starts fast, uses little memory, and can be distributed as a single static binary. Exactly what you need for this.
What It’s NOT
To be clear: this is not AOT compilation (Ahead-of-Time) like GraalVM does with Java or WASM.
Your TypeScript code does not get converted to CPU instructions. It’s still interpreted by JavaScriptCore at runtime. The only thing that changes is that the interpreter comes packaged along with the code.
It’s the same trick that:
pkgdoes for Node.jsPyInstallerdoes for Pythonelectron-builderdoes for Electron apps
It’s not magic. It’s putting the runtime and the code in the same package. That’s why it weighs 100MB — most of it is JavaScriptCore and Bun’s APIs, not Claude Code’s actual code.
What Does Anthropic Gain?
Here’s the crux. Because this change isn’t for you.
Fewer Support Tickets
You know how many problems npm causes? Broken permissions, corrupted cache, Node version conflicts, misconfigured PATH, 800MB node_modules that mysteriously disappear…
Each of those problems is a support ticket. Each support ticket costs money and time. Multiply by the millions of Claude Code users and you’ll understand why Anthropic decided to eliminate npm from the equation.
Frictionless Auto-updates
With npm, updating Claude Code requires the user to run npm update -g @anthropic/claude-code. Some do. Many don’t.
With the native build, updates happen automatically in the background. Anthropic has total control over which version you’re running. For a company that iterates fast and constantly fixes bugs, this is gold.
Controlled Environment
When you get a bug report, the first thing you ask is: “What Node version do you have? What npm version? What operating system?”. With the native build, all that disappears. The execution environment is the same for everyone.
More reproducible bugs = easier to fix bugs.
And What Does the User Gain?
If You Don’t Have Node.js Installed
Clear improvement. Before you needed:
- Install Node.js
- Configure PATH (if it didn’t happen automatically)
- Install npm (comes with Node, but sometimes needs updating)
- Run
npm install -g @anthropic/claude-code - Pray there are no conflicts
Now you need:
| |
For someone who isn’t a developer — a product manager, writer, designer — the difference is huge.
If You Already Have Node.js
Honestly, you gain little. Maybe you avoid some occasional npm problems. Auto-updates are convenient. The native syntax highlighting that only comes in the native build is a nice-to-have.
But if you already had Claude Code working with npm, the change is basically lateral. You won’t notice a difference in day-to-day usage.
The 100MB in Perspective
I know it sounds outrageous. 100MB for a CLI. Our grandparents programmed with 4KB of RAM and here we are downloading 100 megs to run commands.
But let’s be realistic:
- VS Code weighs ~300MB
- Slack ~500MB
- iOS SDK ~30GB
- An average Node.js project has a 500MB+
node_modules
And my favorite: macOS Sequoia includes 45GB of wallpapers.
Forty-five gigabytes. Of wallpapers. 4K videos of floating jellyfish, breaking waves, and northern lights so your Mac has pretty screensavers. That’s 450 times the size of Claude Code. For. Wallpapers.
Claude Code gives you an AI assistant that can write code, execute commands, and manage entire projects. Apple’s wallpapers give you… jellyfish.
In 2026, with 1Gbps fiber and 1TB SSDs as standard, 100MB is statistical noise. You download it in seconds, save it and forget about it.
Is it elegant? No. Does it matter in practice? Not really. And it certainly matters less than the damn jellyfish.
Should You Migrate?
If you have the npm version and it works fine, there’s no rush. You can migrate by running claude install from the npm version.
If you’re installing Claude Code for the first time, use the native build. It’s the recommended option and the one that’ll give you the fewest problems.
If you’re one of those people who gets annoyed by having a 100MB binary taking up space, you can stick with npm. Anthropic says they’ll maintain both options, though it’s clear which one is the future bet.
The Pattern That Repeats
This isn’t new. It’s the same pattern we see over and over in software:
- You start with shared dependencies (DLLs, system libraries, npm packages)
- You run into compatibility, versioning, and distribution problems
- You end up packaging everything together in a fat blob that just works
Docker did the same thing. Electron did the same thing. Bun is doing the same thing.
Is it the most elegant solution? No. Is it the one that causes the fewest problems? Almost always yes.
Sometimes engineering isn’t about finding the prettiest solution, but the one that generates the fewest support tickets. And Anthropic, with their billion-dollar revenue and millions of users, knows this better than anyone.
Related:
- Bun: The Runtime That Wants to Retire Node — Complete Bun tutorial for devs coming from Node, including the Anthropic acquisition.
- 10 GB VM for a Chatbot — Why Claude Desktop puts an entire Ubuntu inside your Mac. Another Anthropic decision that prioritizes “it works” over “elegant”.