October 09, 2023

WebAssembly, WASI, and the Component Model

Matt Butcher Matt Butcher

spin wasi wasm component model

WebAssembly, WASI, and the Component Model

WebAssembly has garnered enough attention that it now has its conferences, forums, and a dedicated community of developers driving its evolution on many fronts. The name “Wasm” and its history have definitely caused some confusion, though. Is it a browser thing (because of the term “Web”)? What does it do? This article covers the basics.

WebAssembly’s Origin Story

WebAssembly (shortened sometimes to Wasm) began as a Mozilla project to add broad language support to the browser.

Initially, Wasm’s goal was shockingly ambitious: Create a binary format that could run on any modern OS and architecture and which any language could compile to. That last bit requires not just a solid standard and a wealth of interest but also every individual language community to implement their own support. There is no greater testament to WebAssembly’s success than the fact that almost all of the major programming languages have added or are in the process of adding support for WebAssembly.

WebAssembly’s niche does not seem to be just in the browser. Wasm is essentially a low-level Virtual Machine (VM) that runs bytecode at near-native speed, taking advantage of common hardware capabilities available on various architectures. Amongst this and a few other reasons, it seems that Wasm has found a firm foothold in other domains. The following video discusses the four domains where Wasm is particularly well-suited and focuses on the one that we at Fermyon find most compelling.

The robust foothold is partly thanks to at least four key features of the WebAssembly design:

  • Security: Unlike other bytecode languages, WebAssembly has a strict security posture of denying access to the system by default, and implementing capability-based control.
  • Cross-platform/architecture: An application compiled to WebAssembly can run on various hardware and software configurations. While Docker containers can effectively run on macOS, Linux and Windows, WebAssembly can run on most operating systems, including macOS, Linux, Windows and UNIX variants. Likewise, the same binary can run on Intel, Arm, and other CPU architectures.
  • Language neutrality: WebAssembly can be programmed using many of the top languages. Languages like C, Rust, Go, TypeScript, Python, Kotlin, and many others also have toolchains or methods available to compile to WebAssembly. There are even Wasm-specific languages (that only compile to Wasm binaries), such as Grain and AssemblyScript. The goal is to allow developers to write code in their preferred languages and then compile it to run in the browser (or other WebAssembly runtimes) at near-native speeds. Which brings us to performance.
  • Performance: WASM is designed for near-native performance. Its low-level binary format enables efficient execution and faster parsing than traditional JavaScript. It’s optimized for quick downloads and has a compact binary format.

These characteristics made WebAssembly a good fit for environments other than just the web browser. But to enable app developers to be productive, WebAssembly was missing a major set of features. It lacked a system interface.

WASI: WebAssembly System Interface

A system interface is a facility that allows an application to interact with the underlying operating system. Operations like reading a file, accessing an environment variable, or requesting a random number are all facilities that rely on the underlying operating system.

The WebAssembly standard did not prescribe how code could access such system resources. This, in fact, was by design. A newer set of specifications, collectively called WebAssembly System Interface (WASI), defines how a WebAssembly application can interact with system resources.

Critical to the design is the security model. An application may request a file, but that does not mean the WebAssembly implementation needs to give that application access to the filesystem. It may, of course. But it could also give access to a virtualized or fake filesystem. Or even respond with an error that such operations are not allowed. But in any case, this should be handled in a way that does not require the developer to write elaborate code.

To make things easy on developers, the early preview of WASI aimed to largely be compatible with POSIX, the Portable Operating System Interface. Since POSIX itself isn’t designed with security as a key consideration, it also drew inspiration heavily from CloudABI, which itself aimed to bring the concept of Capabilities-based security to a POSIX-like system interface. However, even with the positive influence of CloudABI, WASI developers felt this was an awkward union of a new security-focused technology and a specification designed for a more trusting computing environment of a bygone era. Additionally, POSIX and CloudABI are designed in a monolithic and very low-level way that is tied to the C programming language. Both of those aren’t good fits for a system interface that aims to cover a wide range of use cases across all possible platforms. Today, WASI has moved on to provide a secure sandboxing mechanism for applications, streamlining development by offering consistent and safe access to system resources across diverse platforms and in ways that work well across a wide range of programming languages.

WASI’s first widely implemented version was released as “Preview 1.” This version included support for working with:

  • The system clock
  • The random number generator
  • Environment variables
  • The filesystem
  • Standard input, output, and error streams

But as Preview 2 nears completion, we’re seeing not only revisions of these earlier facilities but also the addition of networking capabilities including HTTP and Sockets. Spin already has experimental support for a snapshot of Preview 2.

As WASI continues to evolve, additional system interfaces will be added, including standardized interfaces for more specialized functionality, such as Key-Value stores and machine learning.

Wagi and CGI

To allow developers to build web applications with just WASI Preview 1, we defined a variant of the CGI (Common Gateway Interface) protocol that we called Wagi (WebAssembly Gateway Interface). (Ongoing WASI standards and APIs are defined and developed via proposals.) From the perspective of the code, Wagi is just an implementation of CGI 1.1. But it also articulates how a WASI execution context should present information to a Wagi program (how to construct the required set of environment variables or the HTTP payload).

Tools like Spin include support for Wagi so that any language that supports the WASI standard can instantly be used for writing server-side web applications like serverless functions.

Component Model

Sometimes, WebAssembly’s new Component Model is confused with WASI or treated as part of WASI. Properly speaking, though, it is not. The Component Model describes how two different WebAssembly binaries can communicate with each other.

To do so, it defines an interface description language (IDL) called WIT. WIT is a format for authoring definitions of what functions and data types a WebAssembly binary imports and exports.

An exported function can be used by other WebAssembly binaries. An imported function must be provided (by the host or another WebAssembly binary) before this application can run.

WebAssembly applications can be composed of a group of components linked together into an aggregate application. The following embedded YouTube video introduces this concept in just over one minute (and provides links to Wasm Component Model resources in the description).

Spin

Spin is Fermyon’s open-source developer platform for creating serverless functions in WebAssembly. Since 1.0, Spin has used the component model. And since the project’s inception in 2021, it has implemented the WASI specification (first Preview 1, and now Preview 2).

Spin applications can be more sophisticated than Wagi apps. Spin supports built-in Key/Value Store, SQL Database, dynamic and runtime application configuration, and AI inferencing. Each feature is implemented using the component model and exposed to any program that imports the Spin SDK.

Right now, Fermyon maintains a Spin SDK for only a handful of languages:

  • Go
  • JavaScript/TypeScript
  • Python
  • Rust

We will likely add more SDKs in the future, but for now, this list represents our most frequently requested languages.

Conclusion

WebAssembly, WASI and the Component Model make the WebAssembly ecosystem a powerful environment for building distributed applications and serverless functions. These standards power Spin and Fermyon is dedicated to implementing the standards and also participating in the upstream work by the Bytecode Alliance and W3C to improve the standards and provide excellent open-source implementations.

Get started writing your first WebAssembly application with Spin.


🔥 Recommended Posts


Quickstart Your Serveless Apps with Spin

Get Started