JavaScript was never designed for the server. If that doesn't change soon, JavaScript on the server will be replaced by Rust. The fix needs to happen in the engine. Sound types. Ahead-of-time compilation. Threads with shared objects.
JavaScript engines like JavaScriptCore and V8 have some of the best compiler tech in the world. An open question: with sound types, ahead-of-time compilation for statically typed code, and JITs for everything else, can JavaScript be competitive with Rust and C?
In 2011, Google set out to replace JavaScript with Dart, arguing JavaScript couldn't be fixed by evolving it. Then ES2015 shipped. It's time to do that again.
— Jarred Sumner
Home is in a position to make that fix: it has its own TypeScript checker, a Zig port of Bun's runtime, and a native compiler, all in one tree. This epic tracks the work, based on an audit of origin/main @ d4b219507.
Where things stand
- Sound types. The TS checker matches tsc and nothing stricter;
HMxxxxcodes exist but are never emitted, and the checker quietly synthesizesanywhen it can't model something. The runtime strips types. Home's own checker is gradual (Voidaccepts anything), skips whole statement kinds, and type errors don't stophome build. - Ahead-of-time compilation.
home build x.home→ x64 native works (arm64 is a subset). JS/TS "compile" embeds a bundle into the JIT runtime; nothing lowers TS to native. Native binaries lack PIE, DWARF and a freeing allocator, and Linux releases ship without the JS runtime. - Threads with shared objects. JS Workers work (own JSC heap each; sharing via SAB only). The Home language has no working parallelism: spin-only primitives, an executor that doesn't build, no
spawn, no atomics, no Send/Sync.
Sound types
- #778 fix(types): Home checker never checks return, match, block, assert, trait or impl statements
- #779 fix(types): replace the
Void-means-unknown escape hatch with a realUnknownthat fails closed - #780 fix(cli): make type, parse and import errors fatal in
home build/home check - #781 feat(types): enforce
matchexhaustiveness in the checker - #782 feat(ts): emit Home-only
HMxxxxdiagnostics and accept Home options in tsconfig - #783 feat(ts): distinguish checker-synthesized
anyfrom user-writtenany - #784 feat(ts): opt-in
soundmode that closes TypeScript's known unsoundness holes - #785 feat(runtime):
home run --checkrefuses to run TypeScript with type errors (and skips checking otherwise) - #786 feat(interop): implement the
.d.hmand.d.tsloaders so calls across Home ↔ TypeScript are type-checked - #787 fix(types): make
unsafea real checked boundary - #788 chore(types): wire or delete the unused safety analyses, and make mutable arrays invariant
- #789 feat(validation): generate runtime validators from types for trust boundaries (
validate<T>)
Ahead-of-time compilation
- #790 refactor(build): retire the LLVM JS/TS launcher that copies
hometo /tmp and execs it - #791 feat(aot): ship the JS/TS runtime in Linux release binaries
- #792 feat(aot):
--compile --target=should cross-compile against Home runtime artifacts, not Bun's npm binaries - #793 test(aot): native end-to-end coverage for
home build --compileand--bytecode - #794 perf(aot): cold-start, RSS and binary-size benchmark for compiled servers
- #795 feat(codegen):
--target=<triple>for regular (non-kernel) native builds - #796 feat(codegen): production executable format — PIE, DWARF, libc linkage, object output
- #797 fix(codegen): real allocator with deallocation in native binaries
- #798 fix(build): native
home buildskips comptime, collides module symbols and caches empty blobs - #799 feat(codegen): natively compile a Home HTTP server using the stdlib
- #800 feat(aot): lower type-checked TypeScript (HIR) to native code for a statically resolvable subset
- #801 refactor(codegen): choose the AOT backbone and retire unwired backends
Threads with shared objects
- #802 fix(threading): replace spin-only primitives with futex-backed Mutex/CondVar/RwLock/Semaphore
- #803 fix(threading): honor ThreadAttr, implement CPU affinity and
Semaphore.getValue - #804 fix(async): get the work-stealing executor building and correct
- #805 feat(lang):
spawn, threads and a multi-core executor in the Home language - #806 feat(types): Send/Sync auto traits and thread-aware borrow checking
- #807 feat(codegen): user-space atomic intrinsics and memory ordering
- #808 feat(http): multi-core Home HTTP server
- #809 fix(test): runtime worker tests must prove they ran on Home, not Bun
- #810 test(runtime): admit the Atomics / SharedArrayBuffer / BroadcastChannel corpus on the native VM across platforms
- #811 fix(runtime): eval-realm
structuredCloneandBroadcastChannelmishandle shared memory - #812 RFC(runtime): shared objects across JS workers and Home-native threads
Hybrid: AOT for typed code, JIT for everything else
- #815 feat(aot): run AOT-compiled typed modules alongside the JIT in one process
- #816 feat(ts): generated entry checks where untyped JS calls sound-typed code
- #817 RFC(ts): machine number types and fixed-layout structs for sound TypeScript
- #818 perf(bench): compute benchmarks against Rust and C
- #819 perf(ts-emit): JIT-friendly JS output driven by sound types
Cross-cutting
- #813 docs: reconcile AOT, concurrency and safety claims with the code