⏱️ Lectura: 11 min
WASI Preview 2 es la especificación que permite que los módulos de WebAssembly se ejecuten fuera del navegador, con acceso controlado a archivos, redes y línea de comandos. A diferencia del WebAssembly que corre en Chrome o Firefox, WASI Preview 2 está pensado para servidores, funciones serverless y entornos edge, usando el Component Model para definir interfaces tipadas entre el módulo y el sistema operativo.
📑 En este artículo
Este artículo explica qué cambió con WASI Preview 2, cómo funciona su modelo de seguridad basado en capacidades y cómo compilar y ejecutar un primer componente con wasmtime hoy mismo.
TL;DR
- WASI Preview 2 (WASI 0.2) se lanzó el 25 de enero de 2024 junto con wasmtime 17, del Bytecode Alliance.
- Se basa en el Component Model de WebAssembly, con interfaces descritas en WIT (WebAssembly Interface Types).
- Reemplaza la API estilo POSIX de WASI Preview 1 (2019) por paquetes modulares como wasi-filesystem y wasi-sockets.
- El modelo de seguridad es por capacidades: sin –dir o –tcplisten explícitos, un componente no accede a archivos ni red.
- Rust compila directo al target wasm32-wasip2 desde el toolchain 1.78; Go llega vía TinyGo de forma experimental.
- Runtimes con soporte parcial o total de Preview 2 incluyen WasmEdge, wazero y Wasmer, además de wasmtime.
- En producción lo usan Fermyon Spin, wasmCloud, Envoy (proxy-wasm) y Shopify Functions.
Qué pasó: WASI llega a su versión 0.2
El 25 de enero de 2024 el Bytecode Alliance coordinó el lanzamiento de WASI Preview 2 (también llamado WASI 0.2) junto con la versión 17 de wasmtime, el runtime de referencia escrito en Rust. Ese lanzamiento marcó el punto en el que WASI dejó de depender de una lista fija de funciones estilo POSIX (WASI Preview 1, de 2019) y pasó a describirse con el Component Model de WebAssembly: un sistema de interfaces tipadas escritas en WIT (WebAssembly Interface Types) que define exactamente qué puede pedir un módulo al sistema operativo — y qué no.
La diferencia no es cosmética. WASI Preview 1 exponía una única superficie de syscalls (similar a libc) que todos los runtimes debían implementar igual. WASI Preview 2 divide esa superficie en paquetes independientes — wasi:filesystem, wasi:sockets, wasi:cli, wasi:clocks, wasi:random — que un host puede implementar de forma parcial según el caso de uso. Un runtime embebido en un proxy HTTP no necesita implementar acceso a sockets crudos; uno pensado para funciones serverless sí.
Contexto e historia: de asm.js a los componentes
WebAssembly nació en 2015 como un formato binario portable pensado exclusivamente para el navegador, sucesor de asm.js. Su primera especificación (WebAssembly Core 1.0, estandarizada por el W3C en 2019) definía únicamente aritmética, memoria lineal y llamadas a funciones — sin ninguna forma de tocar el sistema de archivos, la red o el reloj del sistema. Fuera del navegador, cada runtime (wasmtime, Wasmer, WAVM) inventaba su propia API para resolver ese hueco, lo que rompía la portabilidad que era la razón de ser de WebAssembly.
WASI Preview 1, publicado por el Bytecode Alliance en 2019, resolvió ese problema con una capa de compatibilidad estilo POSIX: funciones como fd_read, fd_write o path_open que imitaban las syscalls de Unix. Funcionó, pero heredó las limitaciones del modelo POSIX: descriptores de archivo globales, ausencia de tipos ricos y ninguna forma nativa de componer módulos escritos en lenguajes distintos. WASI Preview 2 se diseñó junto con el Component Model precisamente para resolver ese último punto: permitir que un componente en Rust importe una interfaz implementada por un componente en Go sin pasar por C ABI ni por serialización manual.
Detalles técnicos y rendimiento
La pieza central de WASI Preview 2 es el Component Model. Un componente no es un módulo .wasm más: es un contenedor que declara sus importaciones y exportaciones en WIT, con tipos como string, list, record, variant o resource — tipos que no existen en el WebAssembly Core original, donde solo hay enteros y flotantes de 32/64 bits. El compilador del componente genera automáticamente el código de “canonical ABI” que traduce esos tipos ricos a la memoria lineal plana que WebAssembly sí entiende.
Las interfaces que forman WASI Preview 2 (colectivamente WASI 0.2) incluyen, entre otras:
- wasi:filesystem — apertura, lectura y escritura de archivos y directorios, con descriptores tipados como recursos en vez de enteros crudos.
- wasi:sockets — TCP y UDP, con resolución de nombres vía wasi:sockets/ip-name-lookup.
- wasi:cli — stdin, stdout, stderr y argumentos de línea de comandos.
- wasi:clocks — reloj monotónico y de pared, sin acceso directo a temporizadores del SO.
- wasi:random — generación de números aleatorios seguros, delegada al host.
Sobre rendimiento, no existen todavía benchmarks oficiales publicados por el Bytecode Alliance comparando Preview 1 contra Preview 2 en cifras concretas, así que en vez de citar números sin fuente, la forma correcta de medirlo es reproducirlo vos mismo. Un método simple: compilar el mismo binario con --target wasm32-wasip1 y --target wasm32-wasip2, y comparar el tiempo de arranque con hyperfine:
hyperfine --warmup 3 \
'wasmtime run target/wasm32-wasip1/release/app.wasm' \
'wasmtime run target/wasm32-wasip2/release/app.wasm'
Esto da un número reproducible en tu propia máquina en vez de una cifra de marketing. Lo que sí es verificable sin ambigüedad es si un binario específico es un componente Preview 2 válido — para eso sirve wasm-tools:
wasm-tools component wit target/wasm32-wasip2/release/app.wasm
Si el binario es un componente WASI Preview 2 correcto, este comando imprime el árbol de interfaces WIT que importa y exporta. Si el archivo es un módulo core plano (Preview 1 o WebAssembly sin WASI), el comando falla porque no encuentra la sección de componentes — una forma directa de confirmar en qué “mundo” (world, en terminología WIT) vive tu binario.
Cómo empezar: compilar y ejecutar un componente WASI Preview 2
El camino más directo hoy es Rust, porque el target wasm32-wasip2 está soportado de forma nativa desde la versión 1.78 del toolchain. Los pasos:
rustup target add wasm32-wasip2
cargo new hola-wasi
cd hola-wasi
cargo build --target wasm32-wasip2 --release
wasmtime target/wasm32-wasip2/release/hola-wasi.wasm
Ese comando compila un “hola mundo” y lo ejecuta con wasmtime, que desde su versión 17 soporta Preview 2 sin flags adicionales. Para un ejemplo algo más realista que toque el sistema de archivos:
use std::fs;
fn main() {
let contenido = fs::read_to_string("datos.txt")
.expect("no se pudo leer datos.txt");
println!("Contenido leido: {}", contenido);
}
Si compilás y corrés ese binario tal cual con wasmtime target/wasm32-wasip2/release/hola-wasi.wasm, va a fallar con un error de permiso denegado — no porque el archivo no exista, sino porque WASI aplica seguridad basada en capacidades: un componente no ve ningún directorio del host salvo que se lo concedas explícitamente con --dir:
wasmtime run --dir=. target/wasm32-wasip2/release/hola-wasi.wasm
💭 Clave: WASI no usa una lista negra de permisos prohibidos, usa una lista blanca de capacidades otorgadas. Sin
--dir,--envo--tcplistenexplícitos, el componente no tiene autoridad ambiental sobre el sistema — ni siquiera para leer su propio directorio de trabajo.
Para verificar qué versión de wasmtime tenés instalada y confirmar que soporta Preview 2 (disponible desde la 17.0):
wasmtime -V
Runtimes con soporte de WASI Preview 2
No todos los runtimes de WebAssembly implementan el mismo subconjunto de interfaces WASI 0.2. Antes de elegir uno para producción conviene revisar qué mundo (world) soporta cada uno:
| Runtime | Lenguaje del host | Soporte Preview 2 | Caso de uso típico |
|---|---|---|---|
| wasmtime | Rust | Completo (referencia oficial) | Embeber en apps Rust, CLI, servicios serverless |
| WasmEdge | C++ | Parcial, con extensiones propias para IA | Edge computing, inferencia ligera |
| wazero | Go (sin cgo) | Parcial | Embeber en binarios Go sin dependencias nativas |
| Wasmer | Rust | Parcial | Runtime multi-lenguaje para plugins |
La relación entre un componente WASI y el sistema operativo pasa siempre por el runtime host, que actúa como intermediario y aplica las capacidades otorgadas:
flowchart TD
A["Componente WebAssembly"] --> B["Interfaces WASI (WIT)"]
B --> C["Runtime host (wasmtime)"]
C --> D[("Sistema operativo")]
subgraph Capacidades otorgadas
B
end
Impacto y análisis
El caso de uso donde WASI Preview 2 tiene más tracción hoy es el edge computing y el serverless: plataformas como Fermyon Spin y Fastly Compute construyen sobre componentes WASI porque el arranque en frío de un componente WebAssembly evita levantar un kernel completo como hace un contenedor. wasmCloud usa el Component Model para distribuir “actores” que se comunican mediante interfaces WIT en vez de acoplarse a una librería específica, lo que permite reemplazar la implementación de una capacidad (por ejemplo, una base de datos) sin recompilar el componente que la consume.
En el ecosistema de proxies y gateways, Envoy usa proxy-wasm para cargar filtros HTTP escritos en cualquier lenguaje que compile a WebAssembly, y Shopify usa componentes WASI para las llamadas a “Shopify Functions” que personalizan checkout sin exponer el runtime completo a código de terceros. En todos estos casos el argumento es el mismo: aislamiento por capacidades sin el costo de un contenedor completo, y portabilidad real entre arquitecturas de CPU porque el bytecode es el mismo en x86 y ARM.
⚠️ Ojo: la madurez del ecosistema fuera de Rust todavía es limitada. TinyGo soporta wasm32-wasip2 de forma experimental, Python necesita herramientas adicionales del Bytecode Alliance (componentize-py) para generar componentes en vez de módulos core, y la depuración de un componente con varias capas de composición WIT carece todavía de herramientas maduras equivalentes a un debugger nativo.
Qué sigue
El trabajo activo del Bytecode Alliance se concentra en tres frentes. Primero, wasi:http, la interfaz para hacer y recibir peticiones HTTP directamente desde un componente sin pasar por sockets crudos, clave para que funciones serverless hablen con APIs externas de forma portable. Segundo, wasi:nn, pensada para exponer inferencia de modelos de machine learning a componentes sin que cada uno tenga que empaquetar su propio runtime de IA. Tercero, la propuesta WASI 0.3 incorpora soporte nativo para funciones asíncronas en el Component Model, algo que hoy requiere trabajarse manualmente con callbacks a nivel de host.
En el terreno de la orquestación, proyectos como containerd-wasm-shims permiten que Kubernetes programe componentes WASI como si fueran contenedores normales, usando el mismo kubectl apply pero con un runtime class distinto — una señal de que la intención del ecosistema es que WASI compita directamente con contenedores Linux en las mismas cargas de trabajo, no que sea un nicho aparte.
📖 Resumen en Telegram: Ver resumen
Preguntas frecuentes
¿Qué es WASI?
WASI (WebAssembly System Interface) es el conjunto de interfaces estandarizadas que permite que un módulo de WebAssembly acceda a recursos del sistema operativo — archivos, redes, reloj — sin salir del modelo de seguridad por capacidades de WebAssembly.
¿En qué se diferencia WASI Preview 2 de Preview 1?
WASI Preview 1 (2019) definía una única API estilo POSIX igual para todos los runtimes. WASI Preview 2 (2024) la reemplaza por interfaces modulares descritas en WIT sobre el Component Model, lo que permite componer módulos de distintos lenguajes con tipos ricos.
¿WASI reemplaza a Docker o a los contenedores?
No los reemplaza por completo, pero compite en las mismas cargas de trabajo donde antes solo había contenedores: funciones serverless, plugins de proxy y edge computing, con arranque en frío más rápido y menor superficie de ataque.
¿Qué lenguajes pueden compilar a componentes WASI Preview 2 hoy?
Rust tiene soporte nativo al target wasm32-wasip2 desde el toolchain 1.78. Go llega vía TinyGo de forma experimental, y Python y JavaScript usan herramientas del Bytecode Alliance como componentize-py para generar componentes en vez de módulos core.
¿Cómo se garantiza la seguridad de un componente WASI?
Con un modelo de capacidades: el componente no tiene autoridad ambiental sobre el sistema. El host debe otorgar explícitamente cada permiso — por ejemplo con –dir para filesystem o –tcplisten para sockets — y sin esa concesión la interfaz simplemente no está disponible.
¿Dónde se usa WASI Preview 2 en producción?
Fermyon Spin y Fastly Compute lo usan para funciones serverless, wasmCloud para actores distribuidos, Envoy vía proxy-wasm para filtros HTTP, y Shopify Functions para lógica de checkout de terceros.
Referencias
- Especificación oficial de WASI — repositorio del Bytecode Alliance con las interfaces WIT de cada versión.
- wasmtime en GitHub — runtime de referencia que implementa WASI Preview 2.
- wasi.dev — sitio oficial del proyecto WASI con documentación y guías de las interfaces.
- WebAssembly en MDN — referencia general del formato y su modelo de ejecución.
📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.
0 Comentarios