Skip to content
Learni
View all tutorials
Développement WebAssembly

How to Create Your First Spin Fermyon App in 2026

Lire en français

Introduction

Spin, developed by Fermyon, is an open-source framework for building microservices in WebAssembly (Wasm). Unlike traditional containers, Spin compiles your code to Wasm for ultra-fast, portable execution on any runtime (edge, cloud, on-prem). In 2026, with the rise of edge computing, Spin leads for serverless APIs: minimal latency, millisecond cold starts, and native isolation.

Why adopt it? Imagine Lambda functions 10x faster without vendor lock-in. This beginner tutorial walks you through creating a simple HTTP API in Rust: a GET handler returning JSON, local build, testing, and Fermyon Cloud deployment. At the end, you'll have a live app ready for production. Time: 20 min. Value: solid foundations for scaling to complex apps.

Prerequisites

  • System: macOS, Linux, or Windows (WSL recommended)
  • Rust installed (via rustup.rs)
  • Git (for version control)
  • Free Fermyon Cloud account (optional for deployment)
  • Basic terminal knowledge

Install the Spin CLI

terminal
curl -fsSL https://developer.fermyon.com/downloads/spin/spin-stable-linux-amd64.tar.gz | tar -C /usr/local --strip-components=1 -zxf -

# Sur macOS avec Homebrew
brew install spin

# Vérifier
spin --version

This command downloads and installs the stable Spin CLI (2026-compatible version). On macOS, Homebrew makes it easy. The version check (e.g., v3.x) confirms success, avoiding issues like proxy blocks—use sudo if root access is needed.

Create Your First Spin Project

With the CLI installed, generate a project skeleton. Spin supports Rust, TinyGo, and more; we'll use Rust for its maturity and native performance. The http-rust template creates a basic HTTP handler ready for customization.

Generate the Project

terminal
spin new hello-spin --template http-rust
cd hello-spin

# Explorer la structure
git init  # Optionnel pour versionning
ls -la

The spin new command scaffolds a complete project: Spin.toml for config, src/lib.rs for logic. --template http-rust targets HTTP APIs. Skip empty templates for beginners; ls reveals the auto-generated Cargo.toml, avoiding tedious manual setups.

Configure Spin.toml

Spin.toml defines the component: triggers (HTTP here), bindings (volumes, Redis...), and env vars. It's the YAML-like manifest for deployments. We'll keep it minimal to start.

Spin.toml Configuration File

Spin.toml
spin_manifest_version = "2"

[application]
name = "hello-spin"
version = "1.0.0"

[[trigger.http]]
route = "/..."
component = "hello-spin"

[component]
source = { crate = "hello-spin" }
allowed_http_hosts = []

[component.build]
command = "cargo"

This v2 manifest (2026 standard) links the HTTP trigger to all routes (/...). allowed_http_hosts secures outbound calls. Pitfall: forget spin_manifest_version and the build fails; command = "cargo" automates Wasm compilation.

Implement the HTTP Handler

In src/lib.rs, Spin uses wit-bindgen for standardized Wasm interfaces (WIT). The handler processes HTTP requests: parses JSON, returns 200 OK. Think of it like Express.js, but compiled to pure Wasm.

Main Rust Handler

src/lib.rs
use spin_sdk::http::{IntoResponse, Request, Response};
use spin_sdk::http_component;

#[http_component]
fn handle_request(_req: Request) -> anyhow::Result<impl IntoResponse> {
    let body = r#"{"message": "Hello from Spin Fermyon 2026!"}"#;
    Ok(Response::builder()
        .status(200)
        .header("content-type", "application/json")
        .body(body)?)
}

This minimal handler returns JSON on any POST/GET route. The http_component macro generates the WIT binding. Add anyhow for graceful errors. Pitfall: skip the ? on body() and you'll panic at runtime; test with curl after building.

Build and Test Locally

Compile to optimized Wasm, then run the Spin runtime. Access it at localhost:3000. Built-in logs help with debugging.

Build and Run Locally

terminal
spin build

# Runner local
spin up

# Test en autre terminal
curl http://127.0.0.1:3000/ -

# Stopper : Ctrl+C

spin build cross-compiles to hello-spin.sbg.wasm (Spin Bundle Graph format). spin up enables hot-reload dev mode. Curl tests the endpoint; expect "Hello from Spin...". Pitfall: busy ports—use spin up --port 8080.

Deploy to Fermyon Cloud

For production, push to Fermyon Cloud: free, auto-scaling. spin login authenticates, and deploy publishes.

Cloud Deployment

terminal
spin login  # Crée compte si besoin
spin deploy

# URL live affichée, ex: https://hello-spin.fermyon.app
curl https://<votre-app>.fermyon.app/

deploy handles atomic build + upload. Cloud manages scaling. Pitfall: no login means 401 error; check spin apps list after. Public URL = instant production endpoint.

Best Practices

  • Validate inputs: Use serde for strict JSON, prevent injections.
  • Error handling: Always return Response::builder().status(400) instead of panics.
  • Dynamic bindings: Add Redis/KeyValue via [component.outbound_handler] for stateful apps.
  • Optimize Wasm: Run cargo build --release before spin build for <1MB sizes.
  • CI/CD: Integrate GitHub Actions with spin build && spin deploy.

Common Errors to Avoid

  • Forget spin build: Runtime rejects without generated .wasm.
  • Mismatched routes: Use route = "/api/..." instead of "/..." blocks tests.
  • Missing dependencies: Add spin-sdk = "2" to Cargo.toml or build fails.
  • Ignore cold starts: Test with spin up --timeout 30s to simulate.

Next Steps