Back to News & Insights
Web Development October 6, 2026 · 15 min read

My OSS Projects: Netpack

This is the fifth post in my "My Open-Source Projects" series, where I go through some of the OSS...

My OSS Projects: Netpack

This is the fifth post in my "My Open-Source Projects" series, where I go through some of the OSS projects I started or maintain and tell you the story behind them. So far: AngleSharp, MAGES, Piral, and Electron.NET. This time it's the youngest of the bunch: Netpack - a project that started as an experiment, is not at 1.0 yet, and has a development story that looks very different from everything above.

Netpack is a web bundler written in C#/.NET. You point it at an index.html (like you would with Vite or Parcel) or directly at a .js / .ts file, and it follows everything that is referenced from there, bundles it, optimizes it, and writes the result to disk.

But there's a twist that makes this one worth a post: the CLI is a single native binary (no .NET runtime to install, nothing to warm up), it ships with batteries included (TypeScript, JSX, CSS & CSS Modules, Sass / LESS / PostCSS including Tailwind, images, Vue, Astro, Svelte, Solid, ...), and - since it is written in C# - it can also be used as a plain .NET library or an MSBuild task. That last part is where I see the real future of the project. More on that later.

Can web tooling written in C#/.NET compete with tooling written in Rust, Go, or Zig?

Look at the tools we use every day: esbuild is written in Go, rspack and SWC are written in Rust, Bun is written in Zig. These languages are a great fit for native tooling - and the results speak for themselves. Their developer ergonomics, on the other hand, are... let's say "acquired tastes". I'm a .NET guy. I find C# much more approachable than Rust and more capable than Go. So the question was: could .NET work here? Maybe only under certain constraints - but could it?

I wrote it up back in January 2025, included a lot of caveats, and ended with a question to the community: viable idea or just trash? This post is, in a way, the long answer.

To find out, I started with the most simple approach imaginable - a fake bundler: Open files Read their content Use a regular expression to find things like import statements Resolve the linked modules Look at package.json files to figure out where a package's entry point lives

(If you've read the AngleSharp post you might feel a disturbance right now. Yes: I am aware that "parse code with a regex" is exactly the thing I spent a decade telling people not to do. This was an experiment. Experiments are allowed to be dirty.)

And quite quickly it became clear that plain .NET is, as expected, too slow for this. Not because C# is slow at reading files or walking graphs - the IO and the algorithms are perfectly fine. What kills it is the startup cost.

By default, .NET compiles your code to an intermediate language, and a JIT (just-in-time) compiler turns that into machine code while the program runs. That needs the .NET runtime to be present, started, and then fed with your code every single time. For a long-running server, nobody cares. For a bundler that you start, let finish in a few hundred milliseconds, and then throw away - it's the whole game.

The experiment wasn't over, though, because .NET has an answer for that: AoT (ahead-of-time) compilation. Instead of shipping intermediate language and compiling at runtime, you compile everything to machine code beforehand. The runtime is fused into the binary, there is no JIT, and the program starts right away.

And... it worked. This proved that the IO performance is truly native and that C#/.NET is in the same ballpark as Rust, Zig, or Go for this kind of tool. (There is still a garbage collector in the room, so it is not identical - but the part that kills small tools, the startup, was gone.)

AoT does come with its own challenges. Some libraries cannot be used or need work to be AoT-compatible, and you lose some of the dynamic flexibility that .NET is known for - no runtime reflection, for instance. But for a tool like this, it's a deal I'm happy to take.

Armed with that insight, I replaced the regular expressions with actual code understanding. For the JavaScript side I used a third-party parsing library (Acornima). For HTML and CSS I used my own project, AngleSharp (which, I'm happy to report, is still doing great - it gets a second career here).

The result was a bundler fast enough to compete with the established tools, such as esbuild or rspack - at least on the benchmark projects I used back then. It could only handle plain JavaScript, though. No TypeScript, no source maps, no real configuration. I published the experiment, called it done, and moved on.

For quite a while that's where I saw the project: done. A successful experiment, a proof that the idea works, a repo with a README and some benchmark numbers. The missing features (TypeScript above all) would have required forking the parsing library, and I only wanted to do that "if there is enough buzz around the project".

With the advancements in AI-assisted software development, I took another look. And I realized that many of the missing things - full TypeScript support being the biggest one - could now be added easily.

Here's what made the difference: the AI (mostly Claude) has sufficient understanding of the project to make modifications within the given architecture. That's the key part. The original architecture of the bundler stayed intact. The AI doesn't redesign the thing - it adds missing features and takes care of important bug fixes, inside the structure that was already there.

Want to discuss this further?

Book a free strategy call with our team to see how these insights apply to your specific business goals.

Book a consultation