Porting Kubernetes to TypeScript: The Case Against Browser WASM
Why a lightweight TypeScript translation of the cloud-native control plane beats brute-force WebAssembly compilation for developer tooling.
The dream of running cloud-native infrastructure directly in the browser usually leads developers down a predictable path: compile the existing Go or Rust codebase to WebAssembly (WASM) and call it a day. But for complex, system-level software like Kubernetes, this brute-force approach quickly hits a wall. Between massive binary sizes and the lack of low-level system APIs in the browser sandbox, compiling the actual Kubernetes source code to WASM is highly impractical.
Recently, developer S. Rose from ngrok demonstrated a pragmatic alternative with Webernetes, a partial port of Kubernetes written entirely in TypeScript. By translating the core control plane and simulating the underlying runtime, Webernetes achieves a gzipped bundle size of just 140KiB. It runs pod lifecycles, cluster DNS, networking, deployment controllers, and replica sets directly in a browser tab.
This project highlights a shifting trend in developer advocacy and educational tooling. When it comes to interactive browser environments, architectural simulation is often vastly superior to actual virtualization.
The WebAssembly Wall
Compiling Go code to WASM is notoriously heavy. A basic "hello, world" Go program compiled to WASM and gzipped is roughly 540KiB. Compiling the entire Kubernetes codebase, which is millions of lines of Go, would result in a multi-megabyte payload that is completely unviable for a standard web page load.
More importantly, Kubernetes is designed to interact directly with the Linux kernel. It relies on system calls, raw sockets, control groups (cgroups), and direct file system access to manage containers. The browser's security sandbox does not expose these APIs. Attempting to compile the standard Go implementation of Kubernetes to WASM fails immediately due to these missing system-level hooks.
To bypass this, Webernetes abandons the idea of running the actual Go binaries. Instead, it implements the core Kubernetes specifications in native TypeScript. It replaces the heavy lifting of container virtualization with a simulated environment that mimics the behavior of the Kubernetes API, the kubelet, and the container runtime interface (CRI).
Inside the Browser-Native Control Plane
Webernetes is not a full-blown operating system simulation. It is a highly targeted recreation of the Kubernetes control plane. It consists of several key components:
- A partial kubelet port: Enough of the node agent is implemented to manage pod lifecycles and run liveness and readiness probes.
- Core controllers: Ports of the pod scheduler, namespace controller, kube-proxy, and deployment controller ensure that state changes propagate exactly as they would in a real cluster.
- A simulated Container Network Interface (CNI): Pods are assigned virtual IP addresses and can communicate with each other over a simulated network bridge.
- A browser-native container runtime: Instead of running real Docker or OCI containers, the runtime executes mock workloads defined in TypeScript.
Because the browser cannot pull and run standard Linux container images from Docker Hub, Webernetes uses a custom registry. Workloads are defined as TypeScript classes that extend a base image class, implementing an exec method to handle network requests and process lifecycles.
import * as w8s from "@ngrok/webernetes";
class HelloWorld extends w8s.BaseImage {
static readonly imageName = "hello-world";
static readonly imageVersion = "1.0";
async exec(ctx: w8s.ProcessContext, argv: string[]): Promise<number> {
ctx.listenHttp(8080, async (_ctx, request) => {
return {
status: 200,
body: "Hello, world!",
};
});
return await ctx.waitUntilKilled();
}
}
To run this workload, you register the image with a virtual cluster and apply a standard declarative manifest:
const cluster = new w8s.Cluster();
await cluster.registerImage(HelloWorld);
const [pod] = await cluster.apply([
{
apiVersion: "apps/v1",
kind: "Deployment",
metadata: { name: "hello-world-deployment" },
spec: {
replicas: 1,
selector: {
matchLabels: { app: "hello-world-pod" },
},
template: {
metadata: {
labels: { app: "hello-world-pod" },
},
spec: {
containers: [
{
name: "hello-world-container",
image: "hello-world:1.0",
},
],
},
},
},
},
]);
The Developer Angle: Where This Fits
Webernetes is not a production-ready Kubernetes distribution, nor is it meant to replace local development tools like Minikube or Kind. It lacks support for critical primitives such as ConfigMaps, Secrets, persistent volumes, and resource limits.
However, for developers building educational platforms, interactive documentation, or visual debugging tools, this approach is highly valuable. Spinning up a real Kubernetes cluster in the cloud for every user reading a tutorial is expensive, slow, and a security risk. Webernetes allows authors to embed a fully functional, zero-cost, instant-boot cluster directly inside a blog post or documentation page.
This also highlights an interesting development methodology. The author generated nearly 100,000 lines of code across 629 files in two months by using Large Language Models (LLMs) to translate the Go codebase to TypeScript. To ensure this was not just non-functional "slop," the author reviewed the code line-by-line and wrote hundreds of integration tests to verify that the TypeScript implementation behaves identically to the Go source.
This pattern of using LLMs for strict, test-driven language translation of complex systems is highly repeatable. It allows developers to port mature, battle-tested backend logic to frontend environments without starting from scratch or accepting the performance penalties of WASM.
The Verdict
Webernetes proves that for browser-based developer tooling, emulation and translation are often superior to direct compilation. By shedding the weight of the Linux kernel and the Go runtime, Webernetes delivers a highly accurate, lightweight representation of Kubernetes that loads instantly. As web-based IDEs and interactive docs continue to mature, expect to see more backend control planes undergo this kind of TypeScript translation.
Sources & further reading
- I ported Kubernetes to the browser — ngrok.com
Emeka has spent over a decade tracking threat actors, vulnerability disclosures, and the evolving landscape of application security, bringing a sharp continent-spanning perspective to his reporting. He's known for translating dense CVE advisories into clear, actionable context that developers and security teams alike actually read.
Discussion 0
No comments yet
Be the first to weigh in.