I dismissed Node because it was a super-manual process and experimental.
Bun had some crazy bugs around handling environment variables where they were sort-of baked in at build time instead of evaluated at runtime but only used in some circumstances. I never got to the bottom of it but it was weird enough to put me off Bun because there was clearly something very wrong there and the documentation wasn’t helpful.
Deno worked great. There was one bug I experienced caused by inheriting a node_modules directory that caused it to crash while building, but the fix was released a few days after it was reported.
It’s definitely not as mature as Node, but it’s good enough that I would try it by default for new projects now.
[0] https://twitter.com/deno_land/status/1562771000802279425
I wouldn't pin this on the language, see TigerBeetle as a counter example.
For example, TigerBeetle follows NASA's The Power of Ten Rules for Safety-Critical Code. We require that memory allocation failure be explicitly handled in the control flow, and that no dynamic memory allocation be used after initialization, that all resources (including memory) be explicitly limited, with no hidden allocations.
Our language choices then came down to C or Zig. Zig made most sense.
Zig's correctness philosophy (e.g. extremely explicit control flow) may be different to other languages. But Zig resonated with our own philosophy—in addition to the big examples already given above, we also noticed the little things (e.g. checked arithmetic enabled by default in safe builds).