Cruller is a fork of the last Zig-based Bun release, reduced to the parts needed to run already-built production JavaScript servers and ported to vanilla Zig 0.16.
Repository: GitHub - solenopsys/cruller: fork of Bun · GitHub
The project keeps JavaScriptCore, Bun.serve, HTTP/1-3, WebSockets, fetch, streams, Blob, Request/Response, static serving, and the module resolver for pre-built JavaScript. It removes the package manager, bundler/transpiler, shell, test runner, most CLI dispatch, N-API, SQL clients, archive support, and other development-oriented subsystems.
The interesting part of the port was separating the runtime from Bun’s old patched Zig build integration. Cruller now has a vanilla Zig 0.16 build graph, compatibility shims for APIs changed since Zig 0.15, and a generated-code embedding module so release builds remain portable instead of loading generated JS from the build directory at runtime.
The main design decision is to treat this as a runtime, not a general-purpose Bun replacement. A minimal launcher loads a pre-built entrypoint; features that require package installation, bundling, TypeScript transformation, or bun test are intentionally outside the scope.
Current measurements on Linux x64, compared with the official Bun 1.3.14 binary:
ReleaseFast stripped runtime: 73.0 MiBThe runtime is still work in progress, but Zig semantic checks, release builds, CJS/ESM entrypoints, Node path tests, and an HTTP Bun.serve plus built-in fetch() smoke test currently pass.
Suggested topic tags: showcase, zig-0-16, llm
AI was used as an engineering assistant for parts of the Zig 0.16 migration, build/debug investigation, and focused test work. The project scope, architecture decisions, review of changes, and build/test verification remain maintainer-directed. This is not a purely AI-generated project.
Do you aim to address the critique of the code? I.e., cull the bad design decisions, etc.?
My idea is to strip the system down as much as possible and leave only what is required for production.
Development would be done using the full Bun runtime, while production would use its lightweight fork, Cruller. I do not have the resources of the Oven team to develop and maintain a massive general-purpose runtime, so I want to focus on specific production requirements.
The main goals are:
.zig interface, so it can be embedded into other applications with minimal effort.Cruller is not intended to replace Bun for development. It is a minimal, specialized runtime for executing production code.
In any case, I do not want to throw away such a large codebase that has taken several years to build. It makes more sense to turn it into a convenient embeddable library that can be used throughout the Zig ecosystem.
WeeBull 4
I wondered if someone would do this.
Honestly, I wish you the best of luck. If you do continue this project seriously I’m sure the community will be interested in what you learn. I did start exploring the bun repo myself from the same point (the last Zig release) and I think you’re absolutely correct to slim it down. Looks like you’ve taken about 290k lines of Zig out of the project (712k down to 425k).
Just getting it to the point where the build is zig build looks like it will be a significant milestone to me. I’m currently failing with…
zig 0.16.0 build --build-file build016.zig check
anyzig: build file 'build016.zig'
anyzig: appdata '/home/pauls/.local/share/anyzig'
anyzig: zig '0.16.0' already exists at '/home/pauls/.cache/zig/p/N-V-__8AAFFSVRWqblwBIcA-Yqv-u7sbjsJoww8K0mWaHbmJ'
check
└─ compile obj bzrt-check Debug native 1 errors
error: failed to check cache: 'build/codegen/ZigGeneratedClasses.zig' file_hash FileNotFound
error: 1 compilation errors
I’m highly interested in where this possibly goes, migrating from a DX perspective to a performance I think more aligns with the capabilities and design philosophies of zig. It would be interesting to get some input of the larger zig community on working with this, but I do have some caution when it comes to supporting in specifically Bun.serve and these others here.
That is kind of a crazy undertaking, good luck.
One thing about this whole Bun thing that I find particularly dissatisfying is how Zig compilation speed has been misrepresented. It would be cool if this project were to do whatever work is necessary to be able to make use of incremental compilation and showed the world that Bun could have enjoyed instant rebuilds all along.
Thanks, you found a real clean-checkout bootstrap bug.
build016.zig imported generated modules from build/codegen, but those files
It still requires an installed Bun for that bootstrap because the remaining
The reduction is intentional: Bun remains the development toolchain; Cruller is
First of all, Best of luck!
One thing I’ve been thinking about, the memory issues seem to come from JSC and Zig not playing nice together (GC vs manual memory), not from Zig being bad. Rust doesn’t really fix that either (I still haven’t done much research so I might be wrong), it just the rewrite still has thousand of unsafe blocks (which the bun team will cleanup eventually) at those same issues, because Rust’s type system can’t reason about a garbage collector it doesn’t own. So it seems like the language change helps with bugs in the runtime’s own code, but doesn’t really solve the core JSC/Zig issue problem…
How are you thinking about that issues in Cruller? You mentioned a QuickJS-based memory controller is that related to this?
I initially thought the move to Rust was just a marketing stunt by Claude to show off how “powerful” their AI is. Turns out they hit serious roadblocks — the migration was supposed to take a couple of days, but there’s still no release after three months. There are actually 13,000 unsafe blocks there, not just “thousands,” so the move didn’t seem to provide much real benefit.
If Claude is truly as powerful as they claim, why not migrate JSC itself to Zig instead of switching to Rust? That would have been a real demonstration of capability. Besides, similar memory protection mechanisms to those in Rust could have been implemented selectively for business logic within Zig.
Regarding the memory controller I’m planning to build: it’s not exactly rocket science. I just want to manage JSC’s parameters so that the runtime doesn’t eat 200–300 MB while idling. I doubt I’ll be diving into major engine modifications right now. My current goal is to get it working stably for both business logic and React-based SSR; performance and memory optimization will follow as targeted improvements later on.
WeeBull 10
I’ve thought exactly the same thing. It strikes me that to support a language with garbage collected semantics, you probably need to write an allocator with automated releasing of memory. That might be garbage collection or some other scheme.
WeeBull 11
Is that because the build process was controlled by a high level Typescript process, with the Zig build only being part of that?
alanza 12
no, I think there were structural issues. I’m only repeating third-hand what I heard before, but iirc Bun in Zig used comptime in suboptimal ways that impacted compilation speed, they used usingnamespace (which was a source of slowdowns iirc) well after its deprecation, for a while they depended on a forked version of the compiler for reasons I didn’t understand, etc.
kristoff 13
I believe all usage of usingnamespace was cleaned up, but for example the forked compiler AFAIK was there till the end, it added # prefixes to struct fields meant to be private, but undoing this change is trivial (just remove the pound sign), at which point you should be able to switch back to the normal compiler. That would be an example of something that should be removed to upgrade to a newer version of Zig.
Then there’s the 0.15.0 Reader/Writer switch to runtime interfaces, that also is a big chunk of work I’d imagine, and lastly the async Io stuff in 0.16.0, which is trivial to get working but a lot of edits at that scale.
If for some miracle Bun were to be upgraded all the way to 0.17.0, which contains more important improvements to incremental, then we would be truly be able to see how long it would take for Bun to rebuild.
As a reminder, this is the last compilation times report we saw as the public (post written by somebody working at Bun):
hkupty 14
Really nice initiative, good luck! I truly wish you are able to persevere and harvest good results from this effort!
To me this is the absolutely right mindset. Bun tries to do everything you need for development, which is “unnecessary” (and likely a security hazard) in production. This also makes it more maintainable/sustainable for a single developer. ![]()
I spent 4-6 hours on the migration from 15.2 to version 16; of course, some of the code was removed, but still, the build takes 20 minutes at most, and as far as I remember, there was nothing like 180 minutes there. As for the compiler fork in Bun, it only differs by something like 30 lines of code.
I spent about $5 on the migration. It took a couple of hours with Claude + Python, then DeepSeek (free version) fixed a lot of compilation errors—about 50 of them—then I used Codex a bit more, and overall, there was nothing terrible about it. I definitely didn’t spend $165,000 on tokens, like the Oven team did during their migration to Rust.
Thanks for the feedback and interest in Cruller, everyone. If you have specific ideas or issues, please feel free to share them.
kristoff 17
I think the post is talking about cumulative time.
The benchmark is whether you can run zig build --watch -fincremental on a Linux x64 machine and have the compiler stay on between edits. That will show you exactly how much time it takes for an incremental rebuild of the Zig code. If then the linking is orchestrated externally, this won’t get you all the way to an updated executable, but at least we’ll be able to see how much of that time could have been shaved off by incremental.
Actually, I would go in a different direction: I’d focus on stabilizing a minimal core and moving all connectors—HTTP, HTTP/2, TLS, HTTP/3, ZMQ—into separate plugins. This way, I wouldn’t have to recompile the entire core constantly.
I know it’s not easy, especially with how deeply TLS is integrated into HTTP/3, and there might be some performance trade-offs. Still, I’d prefer to decouple the business logic from the stable core to gain better development velocity.
I’m also exploring a ‘Lego-like’ configuration approach using QuickJS as an orchestration layer to handle component lifecycles (start/destroy). Furthermore, I believe this is critical for microservices—we need a more flexible runtime. Not every service needs HTTP; sometimes you need native QUIC or ZMQ support, and this modular architecture would make that possible.
g41797 19
Bun did not use zig’s std for
So ‘continued on Zig 0.16’ does not mean that
I’d like to understand direction of development
I haven’t touched the internals yet; I just ported it to 0.16.
I think you’re overestimating the value of this porting work. I’ve done high-perf stuff in Zig before (like my zig-httpuring project), hitting 70k+ RPS in a single thread. The problem is that in real-world environments, those gains get wiped out by ingress controllers and infrastructure overhead. That kind of super-optimization is basically Sisyphus’s work—it forces a cascade of changes through the entire stack, only to hit the inherent inefficiencies of the Linux kernel anyway.
My goal here is just to get a stable Zig base so I can modularize the runtime and swap out the bloated C-based I/O for Zig-native code piece by piece, without wasting time on unrealistic optimizations.