WebAssembly Beyond the Browser: Server-Side Use Cases

March 2, 2020

WebAssembly started as a way to run high-performance code in browsers. But its properties—portable, fast, secure, and sandboxed—make it valuable far beyond the browser.

Here’s how WebAssembly is changing server-side computing.

Why WebAssembly Server-Side

The Properties

Portable: Same binary runs everywhere with a Wasm runtime.

Fast startup: Microseconds, not seconds like containers.

Sandboxed: Memory-safe, capability-based security by default.

Language agnostic: Compile from Rust, Go, C/C++, AssemblyScript, and more.

Small: Binaries measured in kilobytes, not megabytes.

Comparison

                 Containers    Native      WebAssembly
Startup time     Seconds       Instant     Microseconds
Image size       100s MB       10s MB      KBs to MBs
Isolation        Process       None        Sandbox
Portability      Good          Poor        Excellent
Security model   OS-level      Trust       Capability-based

Use Cases

Edge Computing

Fast startup and small size make Wasm ideal for edge:

// Rust compiled to Wasm for edge
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn handle_request(url: &str, headers: &str) -> String {
    // Process request at edge
    // Return response
    format!("Processed: {}", url)
}

Cloudflare Workers uses a V8 isolate approach similar to Wasm principles. Fastly’s Compute@Edge runs actual Wasm.

Benefits:

Serverless Functions

Traditional serverless (Lambda, Cloud Functions) has cold start problems:

Container-based:
Request → Cold start (100ms-1s) → Execute → Response

Wasm-based:
Request → Cold start (1-5ms) → Execute → Response

Wasm eliminates cold start penalty for short-lived functions.

Plugin Systems

Extend applications safely with Wasm plugins:

// Host application
func runPlugin(wasmPath string, input []byte) ([]byte, error) {
    // Load Wasm module
    module, err := wasmtime.NewModule(engine, wasmPath)
    if err != nil {
        return nil, err
    }

    // Create instance with limited capabilities
    instance, err := wasmtime.NewInstance(store, module, []wasmtime.AsExtern{})
    if err != nil {
        return nil, err
    }

    // Call plugin function
    process := instance.GetExport(store, "process").Func()
    result, err := process.Call(store, input)

    return result.([]byte), err
}

Real-world examples:

Blockchain and Smart Contracts

Wasm as smart contract execution environment:

Benefits:

Data Processing

Run untrusted code on sensitive data:

// Data transformation in Wasm
#[no_mangle]
pub extern "C" fn transform_record(ptr: *const u8, len: usize) -> *const u8 {
    // Sandboxed data processing
    // Can't access filesystem, network, or memory outside sandbox
    let data = unsafe { std::slice::from_raw_parts(ptr, len) };

    // Transform data
    let result = process(data);

    // Return result
    result.as_ptr()
}

WASI: WebAssembly System Interface

The Missing Piece

Browser Wasm has no system access. WASI provides it safely:

Standard APIs for:
├── Filesystem (scoped)
├── Environment variables
├── Clock/time
├── Random numbers
├── Sockets (upcoming)
└── ... more coming

Capability-Based Security

Programs only get capabilities they’re explicitly granted:

# Run with limited filesystem access
wasmtime --dir=/data::/app-data my-app.wasm

# Program can only access /data, nothing else

Compare to containers:

Example

// WASI-enabled Rust program
use std::fs;
use std::env;

fn main() {
    // These only work if capability is granted at runtime
    let content = fs::read_to_string("/app-data/config.json")
        .expect("Need /app-data access");

    let api_key = env::var("API_KEY")
        .expect("Need API_KEY env var");

    println!("Config loaded");
}

Runtimes

Wasmtime

Mozilla/Bytecode Alliance runtime:

# Install
curl https://wasmtime.dev/install.sh -sSf | bash

# Run
wasmtime my-program.wasm

# With WASI capabilities
wasmtime --dir=/tmp my-program.wasm

Wasmer

Universal runtime with multiple backends:

# Run Wasm packages
wasmer run python/python

# Create standalone executables
wasmer create-exe my-app.wasm -o my-app

WasmEdge

Optimized for edge and cloud:

# Kubernetes integration
kubectl run --image=wasmedge/example-wasi:latest wasm-demo

Comparison

              Wasmtime    Wasmer    WasmEdge
Focus         Standards   Ecosystem Edge/Cloud
JIT           Cranelift   Multiple  LLVM
Embedding     Excellent   Good      Good
WASI support  Complete    Complete  Complete

Compiling to WebAssembly

Rust

First-class Wasm support:

# Add target
rustup target add wasm32-wasi

# Build
cargo build --target wasm32-wasi --release

# Result: target/wasm32-wasi/release/my-app.wasm

Go

# Standard Wasm (browser)
GOOS=js GOARCH=wasm go build -o main.wasm

# TinyGo for smaller binaries and WASI
tinygo build -target=wasi -o main.wasm main.go

C/C++

# Using Emscripten
emcc main.c -o main.wasm

# Using WASI SDK
/opt/wasi-sdk/bin/clang main.c -o main.wasm

AssemblyScript

TypeScript-like syntax compiling to Wasm:

// assembly/index.ts
export function add(a: i32, b: i32): i32 {
  return a + b;
}
asc assembly/index.ts -o build/optimized.wasm

Integration Patterns

Embedding in Applications

// Go application embedding Wasm
package main

import (
    "github.com/bytecodealliance/wasmtime-go"
)

func main() {
    engine := wasmtime.NewEngine()
    store := wasmtime.NewStore(engine)
    module, _ := wasmtime.NewModuleFromFile(engine, "plugin.wasm")

    // Define imports the Wasm module can use
    hostLog := wasmtime.WrapFunc(store, func(ptr int32, len int32) {
        // Host-provided logging
    })

    instance, _ := wasmtime.NewInstance(store, module, []wasmtime.AsExtern{hostLog})

    // Call Wasm function
    run := instance.GetFunc(store, "run")
    result, _ := run.Call(store)
}

Microservices

# Krustlet: Kubernetes for Wasm
apiVersion: v1
kind: Pod
metadata:
  name: wasm-app
spec:
  containers:
    - name: app
      image: example.azurecr.io/my-wasm-app:v1
  tolerations:
    - key: "kubernetes.io/arch"
      operator: "Equal"
      value: "wasm32-wasi"
  nodeSelector:
    kubernetes.io/arch: wasm32-wasi

Function as a Service

// wasmCloud actor
const { Actor, HTTPServer } = require("wasmcloud");

class MyActor extends Actor {
  async handleRequest(request) {
    return {
      statusCode: 200,
      body: JSON.stringify({ message: "Hello from Wasm!" }),
    };
  }
}

Challenges

Ecosystem Maturity

Performance Considerations

Debugging

When to Use WebAssembly

Good Fit

Not Yet Ready

Key Takeaways

WebAssembly is expanding beyond browsers. The same properties that made it successful in browsers—portability, security, performance—make it compelling for servers, edge, and embedded systems.