Every time Figma renders a complex design instantly, or Google Sheets recalculates a huge spreadsheet without lag, or a Shopify store applies a cus...
For further actions, you may consider blocking this person and/or reporting abuse
Great post! I just want to add that yes, WASM is the default runner for inference in the browser, but the real gains you get come from running it on WebGPU.
Great addition, and an important clarification — you're right that I compressed those together. Wasm and WebGPU are doing two different jobs in browser inference: Wasm is the portable, runs-everywhere baseline (it'll work on anything, no special hardware assumed), but the serious performance for real model inference comes from WebGPU getting you actual GPU acceleration. The honest framing is that Wasm makes in-browser inference possible and portable, and WebGPU makes it fast — they're complements, not competitors, and a lot of the ONNX Runtime Web / TensorFlow.js setups will use a Wasm backend as the fallback and WebGPU as the fast path when it's available. So "Wasm for inference" is really "Wasm for reach, WebGPU for speed." Good catch — worth making explicit, because someone reading the piece and expecting native-GPU numbers from the Wasm path alone would be disappointed.
Really good framing, especially treating Wasm as something you reach for when you hit a particular boundary rather than as a JavaScript replacement.
The untrusted-code and plugin cases are the ones I find most interesting, partly because the sandbox changes the architecture question. Instead of asking “how do I stop this extension from doing things it shouldn't?”, you can start from “what capabilities is this extension actually entitled to have?”
That sounds like a small distinction, but it moves authority from convention into the execution boundary. Filesystem, network, host functions, credentials, etc. aren't ambient capabilities the plugin promises not to misuse. They're things the host has to deliberately provide.
I do wonder where the sharp edges move, though. Once the Wasm module is isolated, the host interface becomes the interesting trust boundary. A perfectly sandboxed module with an overly generous set of host capabilities is still overly privileged.
So perhaps there's an eighth wall hiding in the plugin/untrusted-code sections: not just “Can I run code I don't trust?” but “Can I make what that code is allowed to do explicit and inspectable?”
That's a capability I suspect becomes increasingly useful as more of the code we're asked to execute wasn't written by us in the first place.
The shift from "how do I stop this extension misbehaving?" to "what is it actually entitled to have?" is the whole thing — moving authority from convention into the execution boundary, where a capability is something the host deliberately grants, not something the plugin promises not to abuse. And you've found the real eighth wall: once the module is isolated, the host interface becomes the trust boundary, and a perfectly sandboxed module with over-generous capabilities is still over-privileged. So "can I run untrusted code?" is only half — "can I make what it's allowed to do explicit and inspectable?" is the harder, more valuable half. That capability matters more every month, precisely because more of the code we're running wasn't written by us — including, increasingly, code written by a model. Sandboxing is the floor; a legible capability grant is the thing that actually bounds it. Genuinely sharp addition — that's the eighth wall.
I really like “sandboxing is the floor” as the distinction here. Isolation answers where code can execute safely; the capability grant answers what that execution is entitled to affect.
The AI-generated-code angle is what makes this especially interesting to me. If implementation becomes increasingly cheap and disposable, I suspect the durable artifact becomes less “this code was reviewed” and more “this code executed inside an explicit authority boundary.” That feels like a much stronger contract than trusting either the author or the model to behave.
That reframe is a genuinely important one, and I think you're right that it's where things are heading. When implementation gets cheap and disposable — and increasingly isn't even written by a human — the question of who reviewed it starts to matter less, because the reviewer is skimming machine output at machine volume and the author might be a probability distribution. An explicit authority boundary doesn't care who or what wrote the code; it only cares what that code is permitted to touch, which is exactly the property that survives when both authorship and review get cheap and untrustworthy.
What's clever about your version is that it makes the boundary itself the reviewable artifact. You review the capability grant — which is small, explicit, and stable — instead of the code, which is large, disposable, and churning. That inverts the review problem in a way that actually scales, and it's the same move as preferring capability sandboxing over trust: stop trying to certify the intent of the thing running, and bound what any intent can reach. Sharp addition.
That's the piece that clicked for me after your reply: the authority boundary can become the smaller, more stable review artifact while the implementation underneath it churns.
I went off and built a tiny capability-mediated host to see how far that idea actually holds. Two implementations can pass the same correctness test while one reaches for substantially more authority, and the runtime catches the difference without inferring it from the code.
The experiment also broke my first answer to the harder problem. I thought you could observe a component, derive the minimum capability set it exercised, and make that the grant. Then an unobserved but legitimate code path immediately proved the derived grant incomplete. Observation tells you what the component did, not everything it may legitimately need.
So I think your “boundary as the reviewable artifact” framing is right, with an uncomfortable next question attached: who specifies the boundary, and what evidence tells us that specification is complete? That seems to land right back in contract discovery.
That last turn is the good one, and thank you for actually building it. The two-implementations-pass-the-same-test-but-one-grabs-more-authority result is the clean vindication — the runtime catches what correctness can't, without inferring intent from code.
But the way it broke your derive-from-observation answer is the more valuable finding, and it's a familiar shape: observation tells you what the component did, not what it may legitimately need. A passing run is a sample, not a spec, so a derived grant is under-fitted by construction — that's least-observed privilege, not least privilege, and it fails closed in a way that looks like a bug.
So you can't derive the boundary, you have to declare it, and observation's job flips: it audits the declaration instead of building it — catching over-grant (never exercised) and under-grant (reached past it). Not a completeness proof, but incompleteness made loud and legible. Write it up — genuinely.
Really good 🤝, especially the point that Wasm is more useful when it solves a specific bottleneck rather than being treated as a replacement for JavaScript.
The browser-side use cases are particularly interesting. I've been working on client-side PDF processing recently, and Wasm makes a noticeable difference when you start dealing with parsing, document manipulation, and larger files without sending everything to a backend.
I also agree with the point about not using Wasm everywhere. The boundary between JavaScript for the UI and Wasm for the compute-heavy parts seems to be where it makes the most sense.
Client-side PDF processing is a perfect example of the pattern — parsing and manipulating large documents is exactly the compute-heavy, keep-it-off-the-backend case where Wasm earns its place, and doing it locally means the files never leave the user's machine, which is a privacy win on top of the speed. And you've landed on the boundary that actually works: JavaScript for the UI, Wasm for the heavy compute. That division is the whole thing — not "replace JS," but "hand JS the parts it's bad at." Thanks for the real-world data point.
You can also look into what wasmer did with WASIX, it was their attempt at getting more functionality out of WASI, given it was a bit shallow vs POSIX. I've been really deep diving into it since the interviewing started at them, there's still a few holes, but they're not nearly as big as they used to be. Their sdk set is also quite decent.
The concept of WASM is definitely the future we've been wanting 'run anything, anywhere, at native speeds', in that respect, it's amazing! One of the projects I showcased, was a rust-based MCP server, that supports tools from all the major languages, using WASM and supports dynamic tool registration (no restarts needed) and an audit log for every tool call and full isolation for multi-tenancy. That's all stuff possible with WASM, impossible on Node.js.
That being said, WASM as a platform still needs ALOT of work... Take Wasmer for instance, distributed WASM runtimes across the globe, if the server near you goes down, you're directed to the next server, if 2 people on opposite sides, different servers, edit the same thing at the same time, they havent quite figured out CRDT for it yet (I also showcased it implemented to them). So it needs work... But in the age of AI, expect the WASM platform to grow fast and make up for the years it's behind.
WASIX is a great pointer — filling in the POSIX gaps WASI left shallow is exactly what's needed for the "run real server apps" story to hold, and it's good to hear from someone deep in it that the holes are shrinking. Your Rust MCP server is the perfect proof of the thesis: tools from any language, dynamic registration with no restarts, an audit log per tool call, full multi-tenant isolation — that combination genuinely is impossible on Node, and it's the untrusted-code + plugin walls made real. And your honesty about the gaps (the distributed-runtime CRDT problem you had to implement yourself) is the credible part — the platform is years behind where the concept promises, but you're right that AI is about to pour rocket fuel on closing that gap. Great data point from inside the ecosystem. 🤝
My current hiring assignment is porting pgrust to run in wasmer. Just about done with that. That's where I found alot of things that simply arent ready yet. Not too sure how deep you are into Rust, but unwind panics werent supported, they just aborted as a way to 'make it work' at the time, but I fixed that, so pgrust would actually function properly. A perfect example of how WASM works and the clean separation it brings. You can run pgrust, but can you call it complete, if it cant Error handle properly? That's the tiny holes in WASM as a standard that need filling, cuz an app that works isnt good enough, it has to function identical to native, else there'll be edge cases that break it and a broken web service isnt great... I think (theory, no proof) that their current setup where you can select a database during setup on Wasmer, runs the database outside of wasm, because a database is undeniably the most important part of an app to get right and rather than offering a 'partially right' version, they accepted that the platform needs more maturing first and instead left it running as a separate external service outside of their ephemeral wasm instances, to make sure it persists perfectly, every single time, cuz 1 slip up and it's business data lost/corrupted, not just 'oh the app crashed'.
That kinda makes me confident in where WASM is going, the people behind it know the boundary of what's experimental and what needs to be flawless. Cuz it just takes 1 bad app to make someone reject WASM for the next 5-10 years, so when it's advertised as working, it has to work flawlessly.
Porting pgrust into Wasmer is about the best stress-test of the platform's maturity you could pick, and the panic-unwind detail is the perfect example — an app that runs but aborts instead of unwinding isn't complete, because "works in the happy path" and "handles the error path identically to native" are different bars, and the gap between them is exactly where production breaks. That's the WASM-specific version of a theme I keep circling: working isn't the same as correct, and the edge cases are where the truth lives. Your read on why they run the database outside wasm is sharp and, I think, right — the maturity move is knowing which parts you're allowed to ship "mostly right" and which parts have to be flawless, and a database is squarely the second kind. "The app crashed" is recoverable; "the business data corrupted" ends you. And your last point is the real stakes: WASM only gets one reputation, so shipping the flawless-required parts before they're flawless would poison it for a decade. The fact that the people building it clearly know that boundary is the most reassuring thing in your whole comment. Genuinely great view from inside the work — thank you for it. 🤝
The untrusted-code angle is the underrated one for sure. Cold starts in microseconds instead of hundreds of milliseconds is the kind of detail that quietly changes what's practical at the edge.
Exactly — when cold start drops from hundreds of milliseconds to microseconds, "run it at the edge per-request" stops being a compromise and starts being the default.
Really very very nice!! ❤️🙂
Thanks 😊
How did you measure startup time across the two runtimes, and did the Wasm result include compilation?