Skip to content

proposal: all: add wasip3/wasm port #77141

@dicej

Description

@dicej

Proposal Details

This proposes to add support for WASIp3, the next milestone of the WebAssembly System Interface (WASI), which is expected to be released in early 2026.

Background and Motivation

As of this writing, Go supports two GOOS values for GOARCH=wasm: js and wasip1. The former is meant for use in web browsers and standalone JS runtimes, while the latter is meant for standalone WebAssembly runtimes such as Wasmtime (although it can also be used in web browsers via a JS shim). GOOS=wasip1 targets the first milestone of WASI (known as Preview 1 or P1). Since that milestone was released, a second milestone, P2, has been released, and P3 is expected to arrive within the next few months. Here's a high-level summary of those milestones:

  • P1: A shared-memory, POSIX-style interface based on the WITX IDL, with support for stdio, filesystem access, system clocks, environment variables, etc., plus extremely limited networking support.
  • P2: A "shared-nothing"-style interface based on the WebAssembly Component Model, with support for all P1 features, plus complete TCP and UDP networking support, as well as high-level APIs for HTTP client and server applications.
  • P3: A refinement of P2 designed around recently added concurrency support in the Component Model.

The Component Model foundation of P2 and P3 is notable for a few reasons:

  • It provides a lightweight, "shared-nothing" mode of composition such that an application may be composed of multiple subcomponents, each with its own memory and capabilities, and each incapable of directly accessing the memory or capabilities of the others. This can be used to improve supply chain security by isolating third-party code from trusted first-party code.
  • It makes polyglot composition much easier, allowing the developer to define custom, high-level APIs using WIT and generate bindings for a variety of programming languages -- similar to e.g. gRPC, but optimized for local invocations (and without the burden of dealing with distributed system concerns such as partial failures and network errors).
  • P3 provides a composable concurrency model, allowing e.g. goroutines to call Python async functions and vice-versa, each using their native concurrency idioms to suspend and resume as appropriate.
  • P2 and P3 components can be run in web browsers and standalone JS runtimes via jco. The P3 implemention in jco uses JSPI to provide concurrency without requiring an expensive CPS transformation such as the one Go currently uses to support goroutines and panics on Wasm targets.
  • P3's concurrency support means it's the first WASI milestone to support idiomatic use of goroutines. Unlike with P1 and P2, a given goroutine can block on I/O, sleep, etc. without blocking other goroutines. This is possible with or without the CPS transformation mentioned above.

I and others have collaborated to develop a tool for generating Go bindings from WIT interfaces, plus a CLI utility which uses the former to generate bindings, run go build, and output a component which may be run on a P2- or P3-capable runtime such as Wasmtime or jco. Behind the scenes, that tool uses GOOS=wasip1 when compiling and then uses an adapter to transform the compiler output into component that targets P2.

However, that adapter has no way to interact with the Go scheduler, so if any goroutine calls a function in the Go standard library which bottoms out in a call to a P1 import such as poll_oneoff, it will block all goroutines. For the time being (i.e. until GOOS=wasip3 is supported), the only way to allow other goroutines to keep running is to generate and use P3 bindings directly, bypassing the standard library.

Proposal Details

I propose to add preliminary WASIp3 support in two steps:

Step 0

To start with, I propose to add a temporary runtime.wasiOnIdle function to allow the aforementioned wit-bindgen-go tool to bridge the concurrency support in the Component Model with the Go scheduler. This makes it possible to generate concurrency-aware import bindings so that a goroutine can e.g. block on I/O or sleep without blocking other goroutines. It also allows us to experiment with, gather feedback on, and refine Go WASIp3 support outside the Go project in preparation for Step 1, described below.

Note that we could skip this step if desired, in which case we can experiment using a temporary fork of the Go runtime which provides the extra function.

Step 1

Here we would add support for GOOS=wasip3 and make -buildmode=default produce a module which targets the wasi:cli/command world. This would include concurrency support such that e.g. I/O operations only block the calling goroutine, as well as full TCP/UDP networking support. This would be built around the current CPS transform used by the Go compiler to target Wasm, unwinding the Go stack and yielding control to the host as necessary to await I/O. Note that this would require a custom handling of the main function in the compiler and runtime in order to target the Component Model ABI for async function exports.

Future Steps

wasi:http

Here we would add a new implementation of the net/http client APIs which uses the high-level wasi:http interface instead of the low-level wasi:sockets interface, analogous to how js/wasm uses the JS fetch function.

At this point, we could also implement the relevant subset of the net/http server APIs in terms of the wasi:http/service world. Note that this would require a different mode of compilation than for the wasi:cli/command world since wasi:http/service exports a function which accepts an already-parsed HTTP request and returns a not-yet-serialized response, leaving the details of socket I/O, parsing, and serialization to the host.

Native stack switching

At some point, we'll want to ditch the compiler's CPS transform in favor of native host stack switching. This would simplify the compiler and dramatically improve performance.

The Component Model defines intrinsics for creating, yielding from, and resuming cooperative threads, which eliminates the need for a CPS transform. It also anticipates the WebAssembly stack-switching proposal by providing a subset of its features which can be implemented in today's web browsers using JSPI, whereas the stack-switching proposal itself is not yet widely implemented.

Once the compiler has been updated, we'll need to change how the GOOS=wasip3 port bridges Component Model concurrency with the Go scheduler, but this should a be fairly mechanical update and transparent to users.

WASI 1.0

Following WASIp3, the next expected release will be WASI 1.0, a stable release based on a correspondingly stable edition of the Component Model. The current plan is that 1.0 will be a subset of WASIp3, with certain redundant or obsolete features removed. That release would likely be supported in Go as GOOS=wasi, which could simply be an alias for GOOS=wasip3 once we've removed any use of features not in 1.0.

Fun Example

This example demonstrates how to target the wasi:http@0.3.0-rc-2025-09-16 interface in Go using wit-bindgen-go and a lightly patched version of the Go runtime. It exports a function which may be called concurrently by the host, accepting requests and making one or more concurrent outgoing requests. Note that it uses the wasi:http interface directly since net/http has not yet been ported.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ProposalToolProposalIssues describing a requested change to a Go tool or command-line program.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions