45.3 Bun: Ultra-Fast JavaScript Runtime with Built-In TypeScript
Right, let’s talk about Bun. If you’ve been paying attention, you’ve heard the hype: it’s the new JavaScript runtime built from the ground up in Zig, promising to start faster than a caffeinated cheetah and serve you a five-course meal of tooling in a single binary. And you know what? For once, a lot of the hype is real. It’s not magic, but it’s some seriously impressive engineering aimed squarely at making you, the developer, more productive.
The first thing you need to understand about Bun and TypeScript is that it doesn’t “support” TypeScript in the way you’re used to. It consumes it. Natively. There’s no ts-node, no tsc --watch running in a separate process, no plugin configuration in your bundler. You just point Bun at a .ts or .tsx file and it runs it. It feels like a party trick the first time you do it.
# This just works. No setup, no config. It's borderline obscene.
bun run my-script.ts
How It Actually Works (The Black Magic)
Bun achieves this sorcery with its integrated JavaScript/TypeScript transpiler. This thing is written in Zig and is blisteringly fast because it doesn’t use the actual TypeScript compiler (tsc). Instead, it uses a combination of its own parser and the transformer API from the phenomenal swc project to strip out the types and convert your beautiful TypeScript into JavaScript it can execute.
This has a few immediate, critical implications:
It Only Does Type Erasure and Transpilation. It does not perform type checking. Wait, what? Yes, you read that right. Bun will happily run your
.tsfile even if it’s full of blatant type errors. This is the single biggest “gotcha” and the thing that trips up everyone coming fromtscorts-node. Bun assumes you’re handling type checking separately, in your editor or via abun run tsc --noEmitin your CI pipeline.It Respects
tsconfig.json(Mostly). Yourpathsconfiguration? Yep, Bun resolves those. Yourjsxsettings? Absolutely. It reads yourtsconfig.jsonto understand how to transpile your code correctly. But remember, since it’s not usingtsc, some of the more esoteric compiler options might not be supported. Stick to the big ones and you’ll be fine.
The Development Superpowers
This architecture unlocks a developer experience that is, frankly, addictive.
# The built-in test runner is stupid fast and works with TypeScript.
bun test
# Want to run that TypeScript file with hot reloading? Easy.
bun --watch my-script.ts
# The package manager is also built-in and fast. Installing a dependency?
bun add zod # Installs and saves to your package.json in one move.
The speed of these commands, especially from a cold start, is what will ruin you for other tools. It’s the difference between waiting for your coffee to brew and having it injected directly into your veins.
The Rough Edges and Pitfalls
It’s not all rainbows and unicorns. Bun is still young and moving fast.
The Native APIs: Bun has its own set of global APIs for things like reading files (
Bun.file()), HTTP serving (Bun.serve()), and more. They’re great and often more ergonomic than Node’s, but they are not the Node.js APIs. This is the biggest mental shift. If your library or code relies heavily onfs.promises.readFile, it might not work under Bun unless you stick to the Node compatibility mode. Which, to be fair, is excellent—Bun implements a huge chunk of the Node API—but it’s not 100% complete.The Type Checking Blind Spot: I cannot stress this enough: Bun does not type check. You must have your editor (VSCode with the TypeScript language server is the classic) running to get red squiggles. If you save a file with errors and run it with
bun, it will run. This is a feature for speed, not a bug, but it will bite you if you’re not aware.The Moving Target: APIs in Bun are still stabilizing. Something that worked in version 0.1.4 might be deprecated or changed by version 0.5.6. You’re living on the cutting edge, which means you might occasionally get cut. The documentation is good and improving rapidly, but always check it for the latest.
Best Practices for Bun + TypeScript
Separate Checking from Running: Make type checking a separate, explicit step. Use your IDE constantly, and add a script to your
package.jsonto run the official TypeScript compiler for a full project check.{ "scripts": { "check": "tsc --noEmit", "dev": "bun --watch src/index.ts" } }Then run
bun run checkbefore you commit. Your CI should do this too.Embrace the Bun APIs, But Be Cautious: For new projects, using
Bun.fileorBun.serveis fantastic. For existing code or libraries you want to be cross-runtime, lean on Bun’s Node compatibility mode and stick to standard Node APIs or web-standard APIs where possible.Lock Your Bun Version: Because things are changing, pin your Bun version in your CI scripts and for your team. Use
bun -vto check and ensure everyone is on the same page to avoid “but it works on my machine” issues stemming from different runtime versions.
Bun isn’t just a faster Node.js. It’s a reimagining of the entire development toolchain, baked into one coherent binary. The built-in TypeScript support is its flagship feature, and once you get used to the workflow—and more importantly, understand its limitations—you’ll find it incredibly hard to go back to the old, slower, more fragmented way of doing things. Just remember to keep tsc on speed dial for those reality checks.