The current link is just the release notes and covers only the interface-level changes. The announcement post goes into more detail on what's new in WASI 0.3, how it differs from WASI 0.2, and includes examples.
Love/hate with this one. How was I supposed to follow this? I tried, and few things were publicly visible for nearly two years. I last checked in march and it looked like no progress had been made.
That makes me very suspicious of wasiv3. Funny enough, I already implemented a bunch of the promises (pun not intended) and think that freestanding wasm with custom integrations is the more likely future.
The promise of wasi components has not been fulfilled. The market wants to hotload and link artifacts dynamically. The wasi project requires insider wizardry to use it that way: the offering has been statically linking components before you ship. Defeating 99% of the use cases.
I do not like that this has been worked on in the shadows.
I don't think it's fair to say this work has happened in the shadows. I work on CNCF wasmCloud, and I know how hard we try to make this content available.
I mean this, though - what else would you like to see to try and make the content and process more accessible? Are there communities that are doing this really well that we could use for inspiration?
At 18:00 the speaker states something like "It should not be Systems Interface but Standard Interfaces" which honestly sounds like a different project. As an implementer or even as just a user in general, can it be trusted that tomorrow it isn't something completely different? Seems like an odd standard to follow.
(EDIT and aside: Rereading this it reads more dismissive than I meant it. So if this isn't clear: I want WASI to succeed. I think having a widely used system interface is great, but I think many know standards that suffered from scope creep. And while big successful standards for better or for worse at least have a chance of surviving this, WASI as the 0.3 indicates is in its infancy. So I worry about it turning out bad, leading to people abandoning the idea altogether or the standard losing sight of its initial goal. So while this is criticism the only reason I bother to write it in first place is because I badly want it to succeed. I worry that if WASI tries to do too much at once - and I totally understand wanting to do that - it makes it less likely to be successfully implemented and thereby less likely to succeed as a standard.)
I get that. That's not my criticism. My criticism is that you can do say that about many things. With that argument you can essentially encompass everything, which is cool in a way, but also means that the scope is at least bigger than the original - hence what the speaker says.
What I worry about here is that when I think about implementing it the scope will likely grow as well. And while I very much get the wish to encompass things in a standard (I think everyone who ever wrote any kind of specification knows that) a standard doing that extension when the initial goal of being a (commonly used) system interface isn't achieved - at least that's how'd interpret being 0.3 now - then what if that scope extends like that. Will we see full implementations?
To me it seems like maybe it would have made sense to separate that a bit. Something like a WASI based standard. Or something else. The fact that you almost need to change your name like this indicates that you went quite a bit away from the initial goal and doing that before a 1.0 seems like a very early point to get of course for any project. Sure sometimes you find out that you have looked at it from the wrong angle, but honestly this doesn't look like it. This looks a lot more "this is something we can reuse".
> The promise of wasi components has not been fulfilled. The market wants to hotload and link artifacts dynamically. The wasi project requires insider wizardry to use it that way: the offering has been statically linking components before you ship. Defeating 99% of the use cases.
I think both of these points on the spectrum (on the one end, fully static linking of WASI components within a monolithic single-source project; and on the other end, dynamic-at-runtime compiling + linking + loading + "hot instantiating" of arbitrary black-box WASI-component artifacts, with dynamic [presumably reflection-based?] API discovery to drive interaction with those components) are strawmen. There are relatively few "real" use-cases for WASI on either of these ends.
Most of the stuff anyone is really interested in using WASI for (AFAICT, from the use-cases for it I've seen in the wild) involves something closer to the midpoint between these two points. Somewhat dynamic and modular, but with no JIT compilation / components-fetching-components / hot component instantiation / dynamic reflection stuff going on.
Specifically, the "point" of WASI (in my opinion, and in the opinion of most people I've spoken with about it), is to serve as a sort of meta-standard (with tooling) for concrete "pluggable runtime" systems to implement plugin-support SDKs in terms of.
In such "plugin ecosystems", every "plugin" (WASI component) is of the same shape (i.e. exposing the same endpoints, and expecting the same capabilities.) And so the host runtime, and each of its plugins, can be precompiled (separately, in separate projects!) against that shape. And the plugin host can load arbitrary wasm components into a pre-baked plugin "slot" at runtime, because there's no dynamism / introspection / reflection / component framework support required or involved. The plugin host isn't a component itself; it's just ordinary host runtime code, written once. The component framework doesn't load the component; the host runtime does. Etc.
In a sense, this is "custom binding" as you were talking about. But it's custom binding against a WASI-specced target; which is what enables different plugins to be runtime-fungible within the same plugin "slot" from the host's perspective. (While giving you sandboxing for free, unlike the traditional "a plugin is just a DLL that exports certain symbols" approach.) WASI does all the work plugin hosts want of it at component compile/link time: verifying that the plugin is of the expected ABI shape, and guaranteeing sandboxing (by a WASI component inherently being a thing developed to run as an isolate under an abstract machine.) The fact that a compiled+linked WASI-component artifact is a blob of WebAssembly built against certain WIT interfaces, isn't just something tagged onto it by external metadata; it's also something inherent to the structure of the resulting artifact, i.e. a property determinable via static analysis.
At runtime — or slightly earlier, at plugin "install" time — a plugin host might not even keep the component as a component. It might preprocess it into a DLL, or whatever its runtime's equivalent of a DLL is. (A Java class file, say.) The crucial thing was that the component was a component when it was handed off from the downstream developer to the plugin host. Because then any code generated to wrap the component into a host-runtime-native module, is code trusted by the host, rather than code controlled by the downstream developer.
---
If your goal is to compile some one-off blob of WebAssembly code into an artifact that you can then e.g. treat like an old-school ActiveX component from browser JavaScript, then yeah, you don't need WASI at all for that. You're not trying to create a plugin ecosystem. You don't need to spec out a standard "socket" for downstream devs to plug into. You're just "plugging X into a thing that expects only and exactly X". So skip WASI; just use a one-off custom binding. (Though I would note that the WASI work has acted as a forcing function for the WebAssembly-component ABI, enabling you to write much richer custom bindings than you would have been able to write before WASI.)
But if you're:
- developing a FaaS runtime like Cloudflare Workers
- developing a game engine that allows "mods"
- developing a cloud-hosted agent sandbox, where the toplevel is code (that invokes LLMs, that invoke capabilities)
- developing a modern replacement for Wordpress, with an aim to allow just as much extensibility but to not repeat Wordpress's endless vulnerabilities
(etc)
...or, in other words, if you are developing an application or service that O(N) downstream-developed things (workloads, plugins, mods, extensions, whatever you want to call them) all plug into; where you want these things to all plug into your host system in a very precise and controlled way, rather than being given free rein to touch anything they want; and where these interaction patterns can all be described in one of a few very specific shapes, with a precisely definable spec for 1. what API the runtime wants to call into on the component; and 2. what APIs the runtime wants to hand to the component, to enable the component to call those APIs...
...then WASI was developed precisely for you.
And, more specifically, WASI was created so that you could:
1. use WASI to define that API spec (as machine-readable WIT files); and then
2. give that spec, and those WIT files, to the developers in your ecosystem;
3. so that they could then use existing WebAssembly+WASI tooling to build WebAssembly components that target your API spec. (Most likely not by expecting them to independently bootstrap a WebAssembly+WASI dev environment; but rather, by you shipping an SDK that embeds WebAssembly+WASI tooling and your WIT files together.)
(I would also note that this — i.e. "the thing WASI solves for" — is actually a rather rare use-case on the whole. Your average dev isn't [and shouldn't be!] building an ecosystem for API-sandboxed plugins of their code. The few devs that do need to construct their own plugin ecosystems around their project, probably can therefore be expected to go quite deep on learning any required "insider wizardry." If that was even required. Which it generally isn't, when all you're trying to do is to load one of N unknown-until-runtime but statically-defined-ABI-shape plugin components; rather than trying to load arbitrary runtime-generated dynamically-defined-ABI-shape components, allowing those components to load or compile+exec further components, etc.)
Does the stackfull async implementation use the stack-switching proposal? I was under the impression that it's not implemented in most runtimes (very difficult to retrofit into existing implementations), and only available on x86_64 Linux in wasmtime.
No, the stack switching proposal is not used. Stack switching is a set of core Wasm opcodes that permit a guest to change its own stack. Instead of using opcodes inside the Wasm, the stackful async mode of the component model’s ABI calls out into the component model implementation where it can manipulate the stacks with special host powers - JSPI is sufficient on web engines to express this, and wasmtime manages guest stacks in memory.
When stack switching becomes available in all engines, it will be possible to implement this part of the component model in pure Wasm without host magic, e.g. web engines will be able to avoid the call out to JS to use JSPI.
Wrong direction. WASI should be simple and stable. Initially, it was revolving around a simple Unix-like API model and it was close to perfect. Now, there is an opinionated component model which is an unneeded overcomplication that should have never been considered as part of WebAssembly spec IMHO.
A real component model is a separate development and cannot be blindly tied to a particular ecosystem. Otherwise, its main purpose of providing easy interoperability between different ecosystems is totally lost.
I do not know why WebAssembly committee thinks that shoving-in CORBA-like monstrosity is even an acceptable idea. Let's keep WebAssembly lean and fast! Anything extra can (and should) be implemented by other technologies.
The component model is what unlocks relatively type-safe interop between modules written in different languages. Given that Wasm is a runtime target for many languages, this is an entirely appropriate and useful goal.
If you have a host system where you want to expose APIs in an language-agnostic way, IDLs are the best way to do that.
You're also conflating the core WebAssembly work with the WASI work. There is some overlap in people, but WASI is developed separately.
There is a wat (s expression) syntax for the component model. The problem with the wat syntax for both Wasm and the component model is they’re a reflection of a binary format, and therefore are terrible for writing by hand. They’re designed to be written by tools, and the text format is just to help you understand the binary format.
I’ve written Wasm and component model wat extensively over the last decade to develop tests for Wasmtime, and even for an expert it’s a bad experience.
Wit syntax is easy to read and write by hand. There are high quality parsers that can transform it to and from the binary or wat format as needed, and code generators for a wide range of languages. It’s a way, way better experience in every way to deal with wit compared to the wat format.
The present component model is "simple and stable". It is presently providing "interoperability between different ecosystems" and has been for years. It has basically nothing in common with CORBA. All the major problems with the Unix design they ran into that caused them to switch to a component model haven't vanished; the component model is still the best way of solving WASM's major complications that traditional C-based designs don't have. C-based designs, in general, are not better just because they came first; if you were designing systems programming from scratch, you'd want something like WIT (proof: Microsoft has done this twice now).
Note that wasm is still lean and fast - WASI is not part of core wasm, but layered on top.
That is, it is possible to implement wasm without WASI. That is also true for other wasm proposals like WasmGC. It is very possible that parts of the ecosystem will not implement certain proposals if they don't make sense there (e.g. parts of the embedded ecosystem may never add GC, etc.).
I agree. This is saddening. It seems to often happen in "standard first" scenarios for some reason. I was very happy when CloudABI and POSIX were picked as prior art inspiration.
Now it feels like it moved from "what would we need to get things done and achieve our goals?" to "what could be done and which goals could we achieve?"
Maybe I am missing something, but are the recent changes something that people requested?
Yes, you missed people asking for years: away to do interop between languages in WASM, a way to interact with browser APIs without JavaScript from WASM.
Fair enough. Isn't that another topic more tied to WASM compare to what initially claimed to be a "System Interface" and not a language interface or a browser interface?
AIUI, the underlying motivation for the WASM component model is the same as for the early interface types proposal, which has been a planned part of WASM since the very beginning - namely to allow modules written in high-level languages to expose "native" interfaces, without requiring a completely bespoke translation into WASM's lower level facilities. That's a sensible goal, even if achieving this may ultimately involve something that's at least loosely reminiscent of CORBA.
i don't think people calling it CORBA-like are doing it in good faith, but regardless, no we should not do unix apis everywhere for the rest of time please
I think there is a difference between "just copying" and "building upon understood systems and standards".
Also to be fair "just copying" works really really well, especially for standards. The primary goal of standardization is not to invent something new, but to have a target that isn't constantly moving.
If you want to build something new and better do that, and if you are ready to build a standard based of it which is very valid. You can also build them together, and CloudABI which they mention as inspiration in their readme for example did it that way. All valid paths.
But you want to start out simple and something common so that people that make use of the standard have an easy time to implement it. After all having more than one implementation is why you need a standard. Otherwise it's maybe a specification, which again, fair enough.
I can stand behind not copying Unix until the end of time, but "Unix" is a common target that people know how to implement and use. And while not even the authors of Unix claim it's great or even good it is something that people already implement (often enough even when not targeting anything unixy at all) so if your goal is to create a standard that those people can target then abandoning that does seem like a wrong move.
Unix is completely inapplicable to this environment which is inherently managed and intraprocess. Why not send an object saying what you want instead of a plain C struct, or worse a bunch of ints? How do we handle ownership across these boundaries? Why should two high level components be forced to squeeze into a primitive bottleneck between them?
Don't get me wrong: I think C is cute and fills a niche decently well. But that niche is not the one we have here.
The reasons why Unix displaced a bunch of more elegant systems were downward scalability, free distribution, and positioning to take advantage of network effects. Quality was secondary, especially with multiprocessing and networking where a lot had to change, and the designs were not always good.
Even if something lasts due to pure inertia it lasts. And something that lasts is pretty nice if you want a standard to last, or be implemented. The standard usually isn't the thing that you use to proof you can do something better, by being different. Because then everyone will have a harder time adapting it. People implement interfaces they dislike.
Since this is related to Webassembly, Browsers, the Web. The web has a lot of historically baggage, that one might have to work around at times, sometimes more sometimes less. There are good bits and not so good bits and in the end a lot of the time more modern web applications (whether you think they are good or bad) as well as web browsers jump through hoops to do things. For many applications there would be better protocols. But it became the dominant standard, a standard that is actually being used a lot and that is why it has become a success story. It wasn't a hundred times better than everything else. It simply was something that people managed to implement successfully and something where they were willing to deal with shortcomings, because there are great benefits in implementing the same standard as everyone else.
Don't know much about the US constitution, but it seems that it was largely good enough to make people work together that otherwise might have ended up fighting each other. That's what you'd get if everyone had a different idea about what a good constitution is. Maybe things are unclear, and maybe there are uproars because of things, but it doesn't even get to that if people don't agree on a standard or a constitution in first place.
And while over the years I often imagined how great it would be if everyone just used that better standard that has been there for a long time and nobody uses and is completely forgotten, if it ever had any popularity, then everything would be so much better and greater and I wouldn't have to do that senseless thing I am doing now. But if that standard doesn't allow for people to agree with it by implementing it it's essentially worthless (outside of maybe "prior art" consideration).
And like it or not we currently live in a world where designs persist due to pure inertia. But we know that obviously people are willing to implement these which means when a standard comes along that is similar to what already is there then having many people adapting it is realistic. Otherwise it's that super interesting university project that never makes it into anything in the real world.
It clearly hasn't, if you've been paying any attention to security. The Unix security model is that all code that a user runs is 100% trusted. That's absurd in today's world.
The WASI standard is not at 1.0 yet! The people designing WASI are still trying to figure out what people want WASI to be at this point.
This is very likely to involve a lot of major reworking before 1.0, in response to feedback from orgs actually trying to implement WASI-based WebAssembly embeddings into their systems and runtimes. 0.1.x -> 0.2.x was one reworking; 0.2.x -> 0.3.x is another. There may be more of these before an approach is finally settled upon / "locked in" for 1.x.
---
> Let's keep WebAssembly lean and fast!
AFAICT, the entire point of the changes (incl. the more detailed component model) in WASI 0.3 is performance. Not performance of WebAssembly as a black box, though; but rather, performance of the running system as a whole, when a lot of FFI traffic is flowing across the WASI boundary. The richer component model enables lower impedance mismatches and "thinner" FFI-layer implementations.
For example, from the OP:
> WASI 0.2 handed you an output-stream that you wrote into imperatively. WASI 0.3 has you pass in a stream<u8> and get back a future that resolves when the write completes.
For some host languages/runtimes, "imperative blocking write calls" is already how writes against IO descriptors are exposed to the programmer. For those languages, WASI 0.2 made sense.
But in other host languages/runtimes, writes against IO descriptors are inherently non-blocking, returning promises or yielding. For those languages, WASI 0.2 "left performance on the table." WASI 0.2 required such languages to implement a blocking IO write abstraction on top of their non-blocking IO write semantics, in order to pass that blocking-IO-write primitive into the WebAssembly componennt... even if the WebAssembly component was internally concurrent (e.g. compiled from a language like Golang) and so would highly benefit from a non-blocking-IO-write primitive!
Meanwhile, if you require that the host expose a non-blocking-IO-write primitive (as WASI 0.3 does), then for hosts with native non-blocking IO, doing so is free; while for hosts with only blocking IO, non-blocking IO can be "faked" basically for free (i.e. with a global or per-resource linearized write queue on the host side.) And likewise, non-blocking-IO-aware WebAssembly components can freely take advantage of NIO; while WebAssembly components that expect blocking IO only need the tiniest added bit of a codegen shim (`blocking_write(x) => await nonblocking_write(x);`) to fit into a WASI 0.3 world.
In other words, implementing nonblocking IO abstractions on top of blocking IO abstractions costs FFI performance, but implementing blocking IO abstractions on top of nonblocking IO abstractions is "free" (in FFI terms.) Nonblocking IO should therefore be considered the more "primitive" of the two; and so, if you have to choose only BIO or NIO to expose as a capability across a boundary to an unknown peer, NIO should be the one you choose.
---
That being said...
The WASI devs were likely aware of the "FFI optimization opportunities being left on the floor" in WASI 0.2. They likely already wanted to take things in this direction from the beginning. But in WASI 0.2, without async, it was impossible to express the concept of nonblocking IO (i.e. of IO operations returning a promise/future.) They needed to introduce this more "opinionated" (i.e. richer) component model in order to get here.
AFAICT, WASI 0.2 was never intended to be a Release Candidate of the WASI spec. (And WASI 0.3 likely isn't either!)
Rather, WASI 0.2 had areas (like IO) that were purposefully left "under-baked". The WASI team knew people needed some version of these primitives in order for WebAssembly components to usefully integrate into systems at all. But they hadn't yet put in the work on designing how certain aspects of WASI (e.g. async) would work. So they designed WASI 0.2 as a prototype design, based on the limited toolbag of primitives they had already fully agreed upon. Some aspects of WASI turned out to only "want" that limited toolbag of primitives, and so didn't change at all under WASI 0.3 (and might even be in their final shapes.) Other aspects "wanted" things that weren't there, and so experienced over-constrained designs under WASI 0.2, replaced with less-constrained designs under WASI 0.3.
I fully expect there will be more such changes under WASI 0.4. If you don't want to be a guinea pig for major WASI changes, you might want to wait for WASI 1.0. (However long that takes.)
TL;DR: WASI 0.3.0 is the Component Model-based WASI proposal. It adds async/await-style capabilities such as actors and streams, and today is runnable in only one server-side Wasm runtime (it is not supported natively by browsers). Unfortunately it still breaks compatibility with the original WASI proposal and runtimes that supported it.
If your goal is to compile existing, unmodified C/C++ programs and libraries to WebAssembly, WASIX may be a more practical option today ( https://wasix.org/ ). Disclosure: I’m part of Wasmer, the company behind WASIX.
This is funny timing to me, because just the other week I did a dive into WebAssembly and WASI 0.2 (https://jsdw.me/posts/wasm-components/) and assumed that 0.3 would be a while yet as there was no obvious (to me) sign it would come for a while!
Once the tooling is there and Rust has a wasi 0.3 target I'll give it more of a look at :)
I'd love it if WASI modules could introspect their own custom sections (potentially even more introspection than that), but I've never been able to figure out a good way to do this. Seems like a fairly useful feature for a few use cases.
If you have used WASI in the past, can you mention your use case? Very curious if you found it to give you an edge compared to other sandboxing like containers or VMs.
I used WASI to compile an existing 1990's 8-bit assembler cmdline tool written in C for use in a VSCode extension (https://marketplace.visualstudio.com/items?itemName=floooh.v...) - along with regular browser-based WASM compiled via Emscripten for the embedded emulators.
Not sure what to think of all the bells and whistles that were added afterwards (esp the component model), the very first WASI standard was the perfect sweet-spot of simplicity and usefulness. I'm pretty sure I'll never need any of the things that were added afterwards (and I'm going to be slightly pissed when the simple use case - building and running POSIX code - gets more complicated).
WASI is the best format for code submitted by users, entirely untrusted, which is in principle of any complexity but expected to be pretty simple. It works on any platform, in any environment, with extreme and direct control over its access to every resource and its ability to execute at all. Wasmtime's "fuel" feature is not something you can do with containers, and if you can do it with VMs then I don't know about it, but VMs are behemoths for the task of executing a simple function that would in an alternate universe be CEL.
I tinkered with https://extism.org and basically the use case is that they suggest, namely you can extend software in another programming language but without having to setup a container or VMs on the client. They "just" run the code in the browser and it can be JavaScript, sure, but can also be Python, Go, whatever.
It's quite specific though as I'm working on support programming in the browser.
If you are not deep into letting a very specific kind of user extend, it's probably overkill.
Even then it's a very VERY niche thing because it has to be simultaneously :
- someone who is opinionated about a programming language (either because they know too much, i.e. expert, or not enough, i.e beginner)
- is dedicated enough to want to try to build something on top of an existing system
- does not want to bother with solutions you mentioned
We evaluated Extism and concluded that it did basically nothing that WASI and the component model didn't already do out of the box. Was your experience different?
In-process sandboxed llm-generated code execution. Considerably lighter weight, faster to boot (assuming pre-compilation) than Docker or spinning up micro-VMs.
I'm using it for a secure, language agnostic workflow orchestrator. Components have very finely-grained and controller permissions and access to data. They don't even get clocks by default (to mitigate against Spectre-style attacks) and credentials and tainted data are sequestered.
Will WebAssembly ever achieve a real breakthrough? It's been almost 10 years since it came around. HTML, CSS and JavaScript were a breakthrough back in the days. WebAssembly still is not right now; only very few folks or companies use it.
I think its killer use case is actually embedded in non-web places. Tree Sitter parsers require arbitrary programs to be able to parse arbitrary languages. WebAssembly is a natural way to achieve that: write your parser in any language, compile to WebAssembly, use that result in any supported editor. You get sandboxed execution and arbitrary compute.
It has to compete with more domain-adapted use cases though. Does WASM make more sense than eBPF for packet filtering? It doesn't seem to make more sense than JavaScript for making websites. Maybe it makes more sense for deploying edge services (which IIUC is the main use case for WASI).
Plugin architectures are a niche where WASM really shines. Before WASM most plugins were either high performance (loading dynamic libraries) or sandboxed and safe for untrusted plugins (LUA etc). WASM allows you to have your cake and eat it to. You pay with a bit of complexity, but it's in a great and somewhat unique place in the tradeoff space
I think I've seen you comment this on every recent WASM post, and I'm really wondering what you think breakthrough success looks like for a low-level technology like WASM?
Do you expect everyone to hand-code their websites in WASM? Do you expect every webapp be cross-compiled to WASM?
From where I'm standing, WASM is extremely successful in its specific niches: in enabling islands of high-performance in otherwise web-based software, and in sandboxing plugins to native apps/servers.
Many things are possible that weren't possible before. For example, I was able to compile the Dart VM (the compiler + analyzer + VM) to wasm and run it on the web: https://github.com/modulovalue/dart-live it supports hot reload and many other cool features. It runs essentially everywhere and it's a very bare proof of concept for a fully integrated programming development system.
The problem is that things just take time if you have to coordinate across a bunch of languages and teams while trying to make everyone happy.
To give you a sense of what else is coming: the wasm ecosystem is moving towards supporting a component model. Eventually you'll be able to import any piece of code from any programming language that supports it. Wasm interface types will make that possible.
> I was able to compile the Dart VM (the compiler + analyzer + VM) to wasm and run it on the web
Is this really a representative use-case of WASM/WASI? Would'n it be much better to compile Dart to WASM (the Dart SDK even supports "dart compile wasm")?
Your analogy doesn't quite hold. The primary use case of a compilation target is to compile programs, not the compiler itself.
With Dart specifically, "dart compile wasm" already exists precisely for that purpose. Compiling the entire Dart VM (a multi-hundred-thousand-line C++ codebase) to Wasm and then running Dart inside that is a clever in-browser IDE trick, but it's heavy, indirect, and not what Wasm/WASI was designed to showcase. It also sidesteps WasmGC, which is exactly the kind of Wasm evolution that makes Dart-to-Wasm compelling.
It's a silent technology, but I'd argue it has broken through in that most of us already use it daily without knowing. Figma, Google Sheets, Disney+, Prime Video, and much more all have WebAssembly somewhere in their stack.
It's used heavily by major web apps like Figma, it's used to run non-Javascript languages on Cloudflare Workers, many compute-heavy web libraries rely on Wasm modules, many web games rely on Wasm, it's used for safe plugins in some native apps like Microsoft Flight Simulator, amongst other use cases.
My task in question was a number crunching task, basically doing multiply-and-add for 336-bit integers. I wrote a JS version, and a C version compiled into WASM by using Zig. You'd think that WebAssembly would trounce JS here, but it actually didn't.
The JS code had been written carefully to avoid allocations, and also avoiding the built-in JavaScript BigInt. I rolled my own BigInt instead using an array of numbers. Each number, despite being a double, was basically a 48-bit integer. Long multiplication requires splitting a 48-bit integer into two 24-bit integers so an intermediate multiplication result will fit in 48 bits.
The C version used 32x32=64-bit integer math. (Would have been nice if WASM had supported 64x64=128-bit multiplication)
Even with the overhead of using doubles instead of integers, the JavaScript and C versions ran at nearly the same speed. I think the C version was slightly faster, but not significantly. The C version took a lot longer to load, as it had to instantiate a Webassembly object, and had to run glue code to copy things in and out of Webassembly memory.
> and had to run glue code to copy things in and out of Webassembly memory.
Not surprising. The FFI boundary is always a bottleneck. If you can eliminate it, you will see where the WASM JIT shines. You have far more control over mechanical sympathy with C/WASM than JavaScript (though far from perfect).
Also, consider publishing your findings and ask for reviews for optimization opportunities.
Just allowing more than one arraybuffer could go a long way to help with performance. One array buffer for the wasm memory space, then an arraybuffer for each input or output argument.
I mean, it’s another tool. It doesn’t really make an entirely new kind of web app possible, but it’s useful for some specific compute-heavy tasks (with limitations like JS<->WASM being slow). It’s also useful for running not-JS in the browser; I’m building a lighting console with a web UI distributed over multiple devices, and being able to use the exact same structs/representation and algorithms on server and client is pretty neat. It’s like Node, but in reverse! But none of this is cause for paradigm shift, so I don’t think seeing a ”breakthrough” really is relevant.
Wasmtime implements a remote debugging server, so that you can debug guest programs with a recent build of LLDB. Set breakpoints based on the source language symbols, single-step through wasm opcodes, anything you'd expect: https://docs.wasmtime.dev/examples-debugging-guest.html
This! The only way to get to a stable system at least with c/c++ source, where you can hunt bugs, is to have a fairly large unit test coverage. When something fails - add that as test case; run ctest - pray that this is discoverable with tests.
So wasm is a really strange compilation target for systems programming languages.
I mean there _are_ ways to debug it in a browser but they sort of suck.
I'm building a game where you learn to program golang or python and it all runs in webassembly, this way any student chromebook can just pick up and go.
That feels pretty revolutionary, no need to setup your local system to get core concepts.
Even have plans to use postgres in WASM (pglite), and I know a few real time apps use sqlite in WASM.
Hey everyone, we just published the announcement post for WASI 0.3 on the Bytecode Alliance blog:
https://bytecodealliance.org/articles/WASI-0.3
The current link is just the release notes and covers only the interface-level changes. The announcement post goes into more detail on what's new in WASI 0.3, how it differs from WASI 0.2, and includes examples.
Ok, I've swapped that link in at the top and put the submitted URL (https://github.com/WebAssembly/WASI/releases/tag/v0.3.0) in the toptext.
Thank you!
Love/hate with this one. How was I supposed to follow this? I tried, and few things were publicly visible for nearly two years. I last checked in march and it looked like no progress had been made.
That makes me very suspicious of wasiv3. Funny enough, I already implemented a bunch of the promises (pun not intended) and think that freestanding wasm with custom integrations is the more likely future.
The promise of wasi components has not been fulfilled. The market wants to hotload and link artifacts dynamically. The wasi project requires insider wizardry to use it that way: the offering has been statically linking components before you ship. Defeating 99% of the use cases.
I do not like that this has been worked on in the shadows.
I don't think it's fair to say this work has happened in the shadows. I work on CNCF wasmCloud, and I know how hard we try to make this content available.
- Many standing meetings organized around SIGs, all on the public community calendar: https://calendar.google.com/calendar/u/0/newembed?src=events...
- A dedicated Zulip: https://bytecodealliance.zulipchat.com/
- Conferences organized around exactly these topics: Wasm Day, WasmCon, Wasm I/O, and the Bytecode Alliance Plumbers Summit
- CNCF projects: wasmCloud, Spin
- Blogs, many with recordings, summaries, and transcripts: https://bytecodealliance.org/articles/the-road-to-component-..., https://wasmcloud.com/community/, https://spinframework.dev/blog/index
If you want the architectural direction straight from the source, Luke Wagner's keynotes are the best place to start:
- "What is a Component (and Why)?" (WasmCon 2023): https://www.youtube.com/watch?v=tAACYA1Mwv4
- "The Path to Components": https://www.youtube.com/watch?v=phodPLY8zNE
- "Towards a Component Model 1.0" (Wasm I/O 2026): https://www.youtube.com/watch?v=qq0Auw01tH8
I mean this, though - what else would you like to see to try and make the content and process more accessible? Are there communities that are doing this really well that we could use for inspiration?
> - "What is a Component (and Why)?" (WasmCon 2023): https://www.youtube.com/watch?v=tAACYA1Mwv4
At 18:00 the speaker states something like "It should not be Systems Interface but Standard Interfaces" which honestly sounds like a different project. As an implementer or even as just a user in general, can it be trusted that tomorrow it isn't something completely different? Seems like an odd standard to follow.
(EDIT and aside: Rereading this it reads more dismissive than I meant it. So if this isn't clear: I want WASI to succeed. I think having a widely used system interface is great, but I think many know standards that suffered from scope creep. And while big successful standards for better or for worse at least have a chance of surviving this, WASI as the 0.3 indicates is in its infancy. So I worry about it turning out bad, leading to people abandoning the idea altogether or the standard losing sight of its initial goal. So while this is criticism the only reason I bother to write it in first place is because I badly want it to succeed. I worry that if WASI tries to do too much at once - and I totally understand wanting to do that - it makes it less likely to be successfully implemented and thereby less likely to succeed as a standard.)
The speaker is right. Why should "system" interfaces and interfaces from other components ever be fundamentally different?
I get that. That's not my criticism. My criticism is that you can do say that about many things. With that argument you can essentially encompass everything, which is cool in a way, but also means that the scope is at least bigger than the original - hence what the speaker says.
What I worry about here is that when I think about implementing it the scope will likely grow as well. And while I very much get the wish to encompass things in a standard (I think everyone who ever wrote any kind of specification knows that) a standard doing that extension when the initial goal of being a (commonly used) system interface isn't achieved - at least that's how'd interpret being 0.3 now - then what if that scope extends like that. Will we see full implementations?
To me it seems like maybe it would have made sense to separate that a bit. Something like a WASI based standard. Or something else. The fact that you almost need to change your name like this indicates that you went quite a bit away from the initial goal and doing that before a 1.0 seems like a very early point to get of course for any project. Sure sometimes you find out that you have looked at it from the wrong angle, but honestly this doesn't look like it. This looks a lot more "this is something we can reuse".
So join the community and be the change you want to see in the world?
There is an issue open for instantiating modules at runtime: https://github.com/WebAssembly/component-model/issues/423
It's version 0.3...
> The promise of wasi components has not been fulfilled. The market wants to hotload and link artifacts dynamically. The wasi project requires insider wizardry to use it that way: the offering has been statically linking components before you ship. Defeating 99% of the use cases.
I think both of these points on the spectrum (on the one end, fully static linking of WASI components within a monolithic single-source project; and on the other end, dynamic-at-runtime compiling + linking + loading + "hot instantiating" of arbitrary black-box WASI-component artifacts, with dynamic [presumably reflection-based?] API discovery to drive interaction with those components) are strawmen. There are relatively few "real" use-cases for WASI on either of these ends.
Most of the stuff anyone is really interested in using WASI for (AFAICT, from the use-cases for it I've seen in the wild) involves something closer to the midpoint between these two points. Somewhat dynamic and modular, but with no JIT compilation / components-fetching-components / hot component instantiation / dynamic reflection stuff going on.
Specifically, the "point" of WASI (in my opinion, and in the opinion of most people I've spoken with about it), is to serve as a sort of meta-standard (with tooling) for concrete "pluggable runtime" systems to implement plugin-support SDKs in terms of.
In such "plugin ecosystems", every "plugin" (WASI component) is of the same shape (i.e. exposing the same endpoints, and expecting the same capabilities.) And so the host runtime, and each of its plugins, can be precompiled (separately, in separate projects!) against that shape. And the plugin host can load arbitrary wasm components into a pre-baked plugin "slot" at runtime, because there's no dynamism / introspection / reflection / component framework support required or involved. The plugin host isn't a component itself; it's just ordinary host runtime code, written once. The component framework doesn't load the component; the host runtime does. Etc.
In a sense, this is "custom binding" as you were talking about. But it's custom binding against a WASI-specced target; which is what enables different plugins to be runtime-fungible within the same plugin "slot" from the host's perspective. (While giving you sandboxing for free, unlike the traditional "a plugin is just a DLL that exports certain symbols" approach.) WASI does all the work plugin hosts want of it at component compile/link time: verifying that the plugin is of the expected ABI shape, and guaranteeing sandboxing (by a WASI component inherently being a thing developed to run as an isolate under an abstract machine.) The fact that a compiled+linked WASI-component artifact is a blob of WebAssembly built against certain WIT interfaces, isn't just something tagged onto it by external metadata; it's also something inherent to the structure of the resulting artifact, i.e. a property determinable via static analysis.
At runtime — or slightly earlier, at plugin "install" time — a plugin host might not even keep the component as a component. It might preprocess it into a DLL, or whatever its runtime's equivalent of a DLL is. (A Java class file, say.) The crucial thing was that the component was a component when it was handed off from the downstream developer to the plugin host. Because then any code generated to wrap the component into a host-runtime-native module, is code trusted by the host, rather than code controlled by the downstream developer.
---
If your goal is to compile some one-off blob of WebAssembly code into an artifact that you can then e.g. treat like an old-school ActiveX component from browser JavaScript, then yeah, you don't need WASI at all for that. You're not trying to create a plugin ecosystem. You don't need to spec out a standard "socket" for downstream devs to plug into. You're just "plugging X into a thing that expects only and exactly X". So skip WASI; just use a one-off custom binding. (Though I would note that the WASI work has acted as a forcing function for the WebAssembly-component ABI, enabling you to write much richer custom bindings than you would have been able to write before WASI.)
But if you're:
- developing a FaaS runtime like Cloudflare Workers
- developing a game engine that allows "mods"
- developing a cloud-hosted agent sandbox, where the toplevel is code (that invokes LLMs, that invoke capabilities)
- developing a modern replacement for Wordpress, with an aim to allow just as much extensibility but to not repeat Wordpress's endless vulnerabilities
(etc)
...or, in other words, if you are developing an application or service that O(N) downstream-developed things (workloads, plugins, mods, extensions, whatever you want to call them) all plug into; where you want these things to all plug into your host system in a very precise and controlled way, rather than being given free rein to touch anything they want; and where these interaction patterns can all be described in one of a few very specific shapes, with a precisely definable spec for 1. what API the runtime wants to call into on the component; and 2. what APIs the runtime wants to hand to the component, to enable the component to call those APIs...
...then WASI was developed precisely for you.
And, more specifically, WASI was created so that you could:
1. use WASI to define that API spec (as machine-readable WIT files); and then
2. give that spec, and those WIT files, to the developers in your ecosystem;
3. so that they could then use existing WebAssembly+WASI tooling to build WebAssembly components that target your API spec. (Most likely not by expecting them to independently bootstrap a WebAssembly+WASI dev environment; but rather, by you shipping an SDK that embeds WebAssembly+WASI tooling and your WIT files together.)
(I would also note that this — i.e. "the thing WASI solves for" — is actually a rather rare use-case on the whole. Your average dev isn't [and shouldn't be!] building an ecosystem for API-sandboxed plugins of their code. The few devs that do need to construct their own plugin ecosystems around their project, probably can therefore be expected to go quite deep on learning any required "insider wizardry." If that was even required. Which it generally isn't, when all you're trying to do is to load one of N unknown-until-runtime but statically-defined-ABI-shape plugin components; rather than trying to load arbitrary runtime-generated dynamically-defined-ABI-shape components, allowing those components to load or compile+exec further components, etc.)
Does the stackfull async implementation use the stack-switching proposal? I was under the impression that it's not implemented in most runtimes (very difficult to retrofit into existing implementations), and only available on x86_64 Linux in wasmtime.
No, the stack switching proposal is not used. Stack switching is a set of core Wasm opcodes that permit a guest to change its own stack. Instead of using opcodes inside the Wasm, the stackful async mode of the component model’s ABI calls out into the component model implementation where it can manipulate the stacks with special host powers - JSPI is sufficient on web engines to express this, and wasmtime manages guest stacks in memory.
When stack switching becomes available in all engines, it will be possible to implement this part of the component model in pure Wasm without host magic, e.g. web engines will be able to avoid the call out to JS to use JSPI.
Wrong direction. WASI should be simple and stable. Initially, it was revolving around a simple Unix-like API model and it was close to perfect. Now, there is an opinionated component model which is an unneeded overcomplication that should have never been considered as part of WebAssembly spec IMHO.
A real component model is a separate development and cannot be blindly tied to a particular ecosystem. Otherwise, its main purpose of providing easy interoperability between different ecosystems is totally lost.
I do not know why WebAssembly committee thinks that shoving-in CORBA-like monstrosity is even an acceptable idea. Let's keep WebAssembly lean and fast! Anything extra can (and should) be implemented by other technologies.
The component model is what unlocks relatively type-safe interop between modules written in different languages. Given that Wasm is a runtime target for many languages, this is an entirely appropriate and useful goal.
If you have a host system where you want to expose APIs in an language-agnostic way, IDLs are the best way to do that.
You're also conflating the core WebAssembly work with the WASI work. There is some overlap in people, but WASI is developed separately.
Why was the component model not expressed in LISP syntax like the way WAT is ? Why have yet another custom IDL language with bespoke parsing rules ?
There is a wat (s expression) syntax for the component model. The problem with the wat syntax for both Wasm and the component model is they’re a reflection of a binary format, and therefore are terrible for writing by hand. They’re designed to be written by tools, and the text format is just to help you understand the binary format.
I’ve written Wasm and component model wat extensively over the last decade to develop tests for Wasmtime, and even for an expert it’s a bad experience.
Wit syntax is easy to read and write by hand. There are high quality parsers that can transform it to and from the binary or wat format as needed, and code generators for a wide range of languages. It’s a way, way better experience in every way to deal with wit compared to the wat format.
The present component model is "simple and stable". It is presently providing "interoperability between different ecosystems" and has been for years. It has basically nothing in common with CORBA. All the major problems with the Unix design they ran into that caused them to switch to a component model haven't vanished; the component model is still the best way of solving WASM's major complications that traditional C-based designs don't have. C-based designs, in general, are not better just because they came first; if you were designing systems programming from scratch, you'd want something like WIT (proof: Microsoft has done this twice now).
> Let's keep WebAssembly lean and fast!
Note that wasm is still lean and fast - WASI is not part of core wasm, but layered on top.
That is, it is possible to implement wasm without WASI. That is also true for other wasm proposals like WasmGC. It is very possible that parts of the ecosystem will not implement certain proposals if they don't make sense there (e.g. parts of the embedded ecosystem may never add GC, etc.).
I agree. This is saddening. It seems to often happen in "standard first" scenarios for some reason. I was very happy when CloudABI and POSIX were picked as prior art inspiration.
Now it feels like it moved from "what would we need to get things done and achieve our goals?" to "what could be done and which goals could we achieve?"
Maybe I am missing something, but are the recent changes something that people requested?
Yes, you missed people asking for years: away to do interop between languages in WASM, a way to interact with browser APIs without JavaScript from WASM.
Component model enable both using one thing.
Fair enough. Isn't that another topic more tied to WASM compare to what initially claimed to be a "System Interface" and not a language interface or a browser interface?
AIUI, the underlying motivation for the WASM component model is the same as for the early interface types proposal, which has been a planned part of WASM since the very beginning - namely to allow modules written in high-level languages to expose "native" interfaces, without requiring a completely bespoke translation into WASM's lower level facilities. That's a sensible goal, even if achieving this may ultimately involve something that's at least loosely reminiscent of CORBA.
i don't think people calling it CORBA-like are doing it in good faith, but regardless, no we should not do unix apis everywhere for the rest of time please
what would you have it look like?
I disagree. We shouldn't just be copying Unix until the end of time.
I think there is a difference between "just copying" and "building upon understood systems and standards".
Also to be fair "just copying" works really really well, especially for standards. The primary goal of standardization is not to invent something new, but to have a target that isn't constantly moving.
If you want to build something new and better do that, and if you are ready to build a standard based of it which is very valid. You can also build them together, and CloudABI which they mention as inspiration in their readme for example did it that way. All valid paths.
But you want to start out simple and something common so that people that make use of the standard have an easy time to implement it. After all having more than one implementation is why you need a standard. Otherwise it's maybe a specification, which again, fair enough.
I can stand behind not copying Unix until the end of time, but "Unix" is a common target that people know how to implement and use. And while not even the authors of Unix claim it's great or even good it is something that people already implement (often enough even when not targeting anything unixy at all) so if your goal is to create a standard that those people can target then abandoning that does seem like a wrong move.
less copying and more keeping in the spirit of, as it has clearly shown it is a model that is built to last
Unix is completely inapplicable to this environment which is inherently managed and intraprocess. Why not send an object saying what you want instead of a plain C struct, or worse a bunch of ints? How do we handle ownership across these boundaries? Why should two high level components be forced to squeeze into a primitive bottleneck between them?
Don't get me wrong: I think C is cute and fills a niche decently well. But that niche is not the one we have here.
The reasons why Unix displaced a bunch of more elegant systems were downward scalability, free distribution, and positioning to take advantage of network effects. Quality was secondary, especially with multiprocessing and networking where a lot had to change, and the designs were not always good.
That's like saying "the US Constitution has clearly shown it's a model that is built to last"
Sometimes bad designs stick around due to pure inertia
Even if something lasts due to pure inertia it lasts. And something that lasts is pretty nice if you want a standard to last, or be implemented. The standard usually isn't the thing that you use to proof you can do something better, by being different. Because then everyone will have a harder time adapting it. People implement interfaces they dislike.
Since this is related to Webassembly, Browsers, the Web. The web has a lot of historically baggage, that one might have to work around at times, sometimes more sometimes less. There are good bits and not so good bits and in the end a lot of the time more modern web applications (whether you think they are good or bad) as well as web browsers jump through hoops to do things. For many applications there would be better protocols. But it became the dominant standard, a standard that is actually being used a lot and that is why it has become a success story. It wasn't a hundred times better than everything else. It simply was something that people managed to implement successfully and something where they were willing to deal with shortcomings, because there are great benefits in implementing the same standard as everyone else.
Don't know much about the US constitution, but it seems that it was largely good enough to make people work together that otherwise might have ended up fighting each other. That's what you'd get if everyone had a different idea about what a good constitution is. Maybe things are unclear, and maybe there are uproars because of things, but it doesn't even get to that if people don't agree on a standard or a constitution in first place.
And while over the years I often imagined how great it would be if everyone just used that better standard that has been there for a long time and nobody uses and is completely forgotten, if it ever had any popularity, then everything would be so much better and greater and I wouldn't have to do that senseless thing I am doing now. But if that standard doesn't allow for people to agree with it by implementing it it's essentially worthless (outside of maybe "prior art" consideration).
And like it or not we currently live in a world where designs persist due to pure inertia. But we know that obviously people are willing to implement these which means when a standard comes along that is similar to what already is there then having many people adapting it is realistic. Otherwise it's that super interesting university project that never makes it into anything in the real world.
It clearly hasn't, if you've been paying any attention to security. The Unix security model is that all code that a user runs is 100% trusted. That's absurd in today's world.
> WASI should be ... stable.
The WASI standard is not at 1.0 yet! The people designing WASI are still trying to figure out what people want WASI to be at this point.
This is very likely to involve a lot of major reworking before 1.0, in response to feedback from orgs actually trying to implement WASI-based WebAssembly embeddings into their systems and runtimes. 0.1.x -> 0.2.x was one reworking; 0.2.x -> 0.3.x is another. There may be more of these before an approach is finally settled upon / "locked in" for 1.x.
---
> Let's keep WebAssembly lean and fast!
AFAICT, the entire point of the changes (incl. the more detailed component model) in WASI 0.3 is performance. Not performance of WebAssembly as a black box, though; but rather, performance of the running system as a whole, when a lot of FFI traffic is flowing across the WASI boundary. The richer component model enables lower impedance mismatches and "thinner" FFI-layer implementations.
For example, from the OP:
> WASI 0.2 handed you an output-stream that you wrote into imperatively. WASI 0.3 has you pass in a stream<u8> and get back a future that resolves when the write completes.
For some host languages/runtimes, "imperative blocking write calls" is already how writes against IO descriptors are exposed to the programmer. For those languages, WASI 0.2 made sense.
But in other host languages/runtimes, writes against IO descriptors are inherently non-blocking, returning promises or yielding. For those languages, WASI 0.2 "left performance on the table." WASI 0.2 required such languages to implement a blocking IO write abstraction on top of their non-blocking IO write semantics, in order to pass that blocking-IO-write primitive into the WebAssembly componennt... even if the WebAssembly component was internally concurrent (e.g. compiled from a language like Golang) and so would highly benefit from a non-blocking-IO-write primitive!
Meanwhile, if you require that the host expose a non-blocking-IO-write primitive (as WASI 0.3 does), then for hosts with native non-blocking IO, doing so is free; while for hosts with only blocking IO, non-blocking IO can be "faked" basically for free (i.e. with a global or per-resource linearized write queue on the host side.) And likewise, non-blocking-IO-aware WebAssembly components can freely take advantage of NIO; while WebAssembly components that expect blocking IO only need the tiniest added bit of a codegen shim (`blocking_write(x) => await nonblocking_write(x);`) to fit into a WASI 0.3 world.
In other words, implementing nonblocking IO abstractions on top of blocking IO abstractions costs FFI performance, but implementing blocking IO abstractions on top of nonblocking IO abstractions is "free" (in FFI terms.) Nonblocking IO should therefore be considered the more "primitive" of the two; and so, if you have to choose only BIO or NIO to expose as a capability across a boundary to an unknown peer, NIO should be the one you choose.
---
That being said...
The WASI devs were likely aware of the "FFI optimization opportunities being left on the floor" in WASI 0.2. They likely already wanted to take things in this direction from the beginning. But in WASI 0.2, without async, it was impossible to express the concept of nonblocking IO (i.e. of IO operations returning a promise/future.) They needed to introduce this more "opinionated" (i.e. richer) component model in order to get here.
AFAICT, WASI 0.2 was never intended to be a Release Candidate of the WASI spec. (And WASI 0.3 likely isn't either!)
Rather, WASI 0.2 had areas (like IO) that were purposefully left "under-baked". The WASI team knew people needed some version of these primitives in order for WebAssembly components to usefully integrate into systems at all. But they hadn't yet put in the work on designing how certain aspects of WASI (e.g. async) would work. So they designed WASI 0.2 as a prototype design, based on the limited toolbag of primitives they had already fully agreed upon. Some aspects of WASI turned out to only "want" that limited toolbag of primitives, and so didn't change at all under WASI 0.3 (and might even be in their final shapes.) Other aspects "wanted" things that weren't there, and so experienced over-constrained designs under WASI 0.2, replaced with less-constrained designs under WASI 0.3.
I fully expect there will be more such changes under WASI 0.4. If you don't want to be a guinea pig for major WASI changes, you might want to wait for WASI 1.0. (However long that takes.)
Also see, from yesterday:
https://news.ycombinator.com/item?id=48448083
“The Road to the WASM Component Model 1.0” (bytecodealliance.org)
95 points | by emschwartz | 99 comments
Congrats on the release to the WASI team.
TL;DR: WASI 0.3.0 is the Component Model-based WASI proposal. It adds async/await-style capabilities such as actors and streams, and today is runnable in only one server-side Wasm runtime (it is not supported natively by browsers). Unfortunately it still breaks compatibility with the original WASI proposal and runtimes that supported it.
If your goal is to compile existing, unmodified C/C++ programs and libraries to WebAssembly, WASIX may be a more practical option today ( https://wasix.org/ ). Disclosure: I’m part of Wasmer, the company behind WASIX.
If you don't want to download the .tar.gz I think you can browse the content for this release (.wit interface files) here on GitHub: https://github.com/WebAssembly/WASI/tree/v0.3.0/proposals
This is funny timing to me, because just the other week I did a dive into WebAssembly and WASI 0.2 (https://jsdw.me/posts/wasm-components/) and assumed that 0.3 would be a while yet as there was no obvious (to me) sign it would come for a while!
Once the tooling is there and Rust has a wasi 0.3 target I'll give it more of a look at :)
I'd love it if WASI modules could introspect their own custom sections (potentially even more introspection than that), but I've never been able to figure out a good way to do this. Seems like a fairly useful feature for a few use cases.
If you have used WASI in the past, can you mention your use case? Very curious if you found it to give you an edge compared to other sandboxing like containers or VMs.
I used WASI to compile an existing 1990's 8-bit assembler cmdline tool written in C for use in a VSCode extension (https://marketplace.visualstudio.com/items?itemName=floooh.v...) - along with regular browser-based WASM compiled via Emscripten for the embedded emulators.
For this use case the old-school POSIX-style WASI was just perfect and completely hassle-free via the WASI SDK (https://github.com/webassembly/wasi-sdk).
Not sure what to think of all the bells and whistles that were added afterwards (esp the component model), the very first WASI standard was the perfect sweet-spot of simplicity and usefulness. I'm pretty sure I'll never need any of the things that were added afterwards (and I'm going to be slightly pissed when the simple use case - building and running POSIX code - gets more complicated).
WASI is the best format for code submitted by users, entirely untrusted, which is in principle of any complexity but expected to be pretty simple. It works on any platform, in any environment, with extreme and direct control over its access to every resource and its ability to execute at all. Wasmtime's "fuel" feature is not something you can do with containers, and if you can do it with VMs then I don't know about it, but VMs are behemoths for the task of executing a simple function that would in an alternate universe be CEL.
I tinkered with https://extism.org and basically the use case is that they suggest, namely you can extend software in another programming language but without having to setup a container or VMs on the client. They "just" run the code in the browser and it can be JavaScript, sure, but can also be Python, Go, whatever.
It's quite specific though as I'm working on support programming in the browser.
If you are not deep into letting a very specific kind of user extend, it's probably overkill.
Even then it's a very VERY niche thing because it has to be simultaneously :
- someone who is opinionated about a programming language (either because they know too much, i.e. expert, or not enough, i.e beginner)
- is dedicated enough to want to try to build something on top of an existing system
- does not want to bother with solutions you mentioned
We evaluated Extism and concluded that it did basically nothing that WASI and the component model didn't already do out of the box. Was your experience different?
> If you have used WASI in the past, can you mention your use case?
For my "TagLib for TypeScript" library, I use WASI for local filesystem operations when used with Node.js/Deno/Bun. https://github.com/CharlesWiltgen/taglib-wasm
Extending my Rust binary with a marketplace of WASM-based extensions like VSCode
In-process sandboxed llm-generated code execution. Considerably lighter weight, faster to boot (assuming pre-compilation) than Docker or spinning up micro-VMs.
I'm using it for a secure, language agnostic workflow orchestrator. Components have very finely-grained and controller permissions and access to data. They don't even get clocks by default (to mitigate against Spectre-style attacks) and credentials and tainted data are sequestered.
The best usage example of WASI I know of is the Zig compiler: https://ziglang.org/news/goodbye-cpp/
Edge rural farm systems
extending software with a plugin system
Is there some Zig code demonstrating how to use all the changes in a Zig program that compiles to WASI 0.3.0?
Will WebAssembly ever achieve a real breakthrough? It's been almost 10 years since it came around. HTML, CSS and JavaScript were a breakthrough back in the days. WebAssembly still is not right now; only very few folks or companies use it.
I think its killer use case is actually embedded in non-web places. Tree Sitter parsers require arbitrary programs to be able to parse arbitrary languages. WebAssembly is a natural way to achieve that: write your parser in any language, compile to WebAssembly, use that result in any supported editor. You get sandboxed execution and arbitrary compute.
It has to compete with more domain-adapted use cases though. Does WASM make more sense than eBPF for packet filtering? It doesn't seem to make more sense than JavaScript for making websites. Maybe it makes more sense for deploying edge services (which IIUC is the main use case for WASI).
Plugin architectures are a niche where WASM really shines. Before WASM most plugins were either high performance (loading dynamic libraries) or sandboxed and safe for untrusted plugins (LUA etc). WASM allows you to have your cake and eat it to. You pay with a bit of complexity, but it's in a great and somewhat unique place in the tradeoff space
I think I've seen you comment this on every recent WASM post, and I'm really wondering what you think breakthrough success looks like for a low-level technology like WASM?
Do you expect everyone to hand-code their websites in WASM? Do you expect every webapp be cross-compiled to WASM?
From where I'm standing, WASM is extremely successful in its specific niches: in enabling islands of high-performance in otherwise web-based software, and in sandboxing plugins to native apps/servers.
It's already a breakthrough in my opinion.
Many things are possible that weren't possible before. For example, I was able to compile the Dart VM (the compiler + analyzer + VM) to wasm and run it on the web: https://github.com/modulovalue/dart-live it supports hot reload and many other cool features. It runs essentially everywhere and it's a very bare proof of concept for a fully integrated programming development system.
The problem is that things just take time if you have to coordinate across a bunch of languages and teams while trying to make everyone happy.
To give you a sense of what else is coming: the wasm ecosystem is moving towards supporting a component model. Eventually you'll be able to import any piece of code from any programming language that supports it. Wasm interface types will make that possible.
> I was able to compile the Dart VM (the compiler + analyzer + VM) to wasm and run it on the web
Is this really a representative use-case of WASM/WASI? Would'n it be much better to compile Dart to WASM (the Dart SDK even supports "dart compile wasm")?
this is a confusing question; why would it be much better to e.g. compile a C program for x86 linux musl but not the C compiler?
Your analogy doesn't quite hold. The primary use case of a compilation target is to compile programs, not the compiler itself.
With Dart specifically, "dart compile wasm" already exists precisely for that purpose. Compiling the entire Dart VM (a multi-hundred-thousand-line C++ codebase) to Wasm and then running Dart inside that is a clever in-browser IDE trick, but it's heavy, indirect, and not what Wasm/WASI was designed to showcase. It also sidesteps WasmGC, which is exactly the kind of Wasm evolution that makes Dart-to-Wasm compelling.
It's a silent technology, but I'd argue it has broken through in that most of us already use it daily without knowing. Figma, Google Sheets, Disney+, Prime Video, and much more all have WebAssembly somewhere in their stack.
WebAssembly is used in all sorts of ways.
It's used heavily by major web apps like Figma, it's used to run non-Javascript languages on Cloudflare Workers, many compute-heavy web libraries rely on Wasm modules, many web games rely on Wasm, it's used for safe plugins in some native apps like Microsoft Flight Simulator, amongst other use cases.
It has, but its usually just an optimization, so goes unnoticed
WASI stands for WebAssembly System Interface.
It has little to do with the webassembly in the browser.
I use it to extend a native application, for example. No browser in sight at all.
WebAssembly doesn't beat JavaScript in performance, and that is embarrassing.
That's not accurate. I Googled for a recent performance benchmark and found this which indicates Wasm offers a notable performance gain: https://medium.com/@hashbyt/webassembly-vs-javascript-perfor...
My task in question was a number crunching task, basically doing multiply-and-add for 336-bit integers. I wrote a JS version, and a C version compiled into WASM by using Zig. You'd think that WebAssembly would trounce JS here, but it actually didn't.
The JS code had been written carefully to avoid allocations, and also avoiding the built-in JavaScript BigInt. I rolled my own BigInt instead using an array of numbers. Each number, despite being a double, was basically a 48-bit integer. Long multiplication requires splitting a 48-bit integer into two 24-bit integers so an intermediate multiplication result will fit in 48 bits.
The C version used 32x32=64-bit integer math. (Would have been nice if WASM had supported 64x64=128-bit multiplication)
Even with the overhead of using doubles instead of integers, the JavaScript and C versions ran at nearly the same speed. I think the C version was slightly faster, but not significantly. The C version took a lot longer to load, as it had to instantiate a Webassembly object, and had to run glue code to copy things in and out of Webassembly memory.
> and had to run glue code to copy things in and out of Webassembly memory.
Not surprising. The FFI boundary is always a bottleneck. If you can eliminate it, you will see where the WASM JIT shines. You have far more control over mechanical sympathy with C/WASM than JavaScript (though far from perfect).
Also, consider publishing your findings and ask for reviews for optimization opportunities.
it is faster, but there is unacceptable loss when passing data to/from js, definitely an area needing improvement (or having to do it less)
https://hacks.mozilla.org/2026/02/making-webassembly-a-first...
Just allowing more than one arraybuffer could go a long way to help with performance. One array buffer for the wasm memory space, then an arraybuffer for each input or output argument.
Wasm multiple memories is a thing now
I mean, it’s another tool. It doesn’t really make an entirely new kind of web app possible, but it’s useful for some specific compute-heavy tasks (with limitations like JS<->WASM being slow). It’s also useful for running not-JS in the browser; I’m building a lighting console with a web UI distributed over multiple devices, and being able to use the exact same structs/representation and algorithms on server and client is pretty neat. It’s like Node, but in reverse! But none of this is cause for paradigm shift, so I don’t think seeing a ”breakthrough” really is relevant.
You said the exact same thing a couple days ago. You don't know what you don't know.
WebAssembly has been a great success thanks to its excellent initial design.
for me its undebuggability.
-"hey, look at our C Rust FORTRAN to WASM translator, blahblah"
-"uhm, cool, how do I debug it?"
-"yeah...about that...you cant!"
Wasmtime implements a remote debugging server, so that you can debug guest programs with a recent build of LLDB. Set breakpoints based on the source language symbols, single-step through wasm opcodes, anything you'd expect: https://docs.wasmtime.dev/examples-debugging-guest.html
Why can’t you?
This! The only way to get to a stable system at least with c/c++ source, where you can hunt bugs, is to have a fairly large unit test coverage. When something fails - add that as test case; run ctest - pray that this is discoverable with tests.
So wasm is a really strange compilation target for systems programming languages.
I mean there _are_ ways to debug it in a browser but they sort of suck.
I'm building a game where you learn to program golang or python and it all runs in webassembly, this way any student chromebook can just pick up and go.
That feels pretty revolutionary, no need to setup your local system to get core concepts.
Even have plans to use postgres in WASM (pglite), and I know a few real time apps use sqlite in WASM.