spin Documentation

Spin is the open source developer tool for building and running serverless applications powered by WebAssembly.

6,471 stars Rust Rust 1 file ยท ~6,242 tokens #serverless#spin#webassembly
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy spin on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name spin -p 8888:8888 --restart always otel/opentelemetry-collector-contrib:0.98.0
Configured Services & Ports
โš™๏ธ otel-collector
image: otel/opentelemetry-collector-contrib:0.98.0
๐Ÿ”Œ Ports: 8888:8888, 8889:8889, 4317:4317, 4318:4318
โš™๏ธ jaeger
image: jaegertracing/all-in-one:latest
๐Ÿ”Œ Ports: 16686:16686, 14268, 14250
โš™๏ธ tempo
image: grafana/tempo:2.4.1
๐Ÿ”Œ Ports: 4318, 7999:7999
โš™๏ธ prometheus
image: prom/prometheus:latest
๐Ÿ”Œ Ports: 9090:9090
โš™๏ธ grafana
image: grafana/grafana:10.4.2
๐Ÿ”Œ Ports: 5050:3000
โš™๏ธ loki
image: grafana/loki:2.9.8
๐Ÿ”Œ Ports: 3100:3100
docker-compose.yml
yaml (docker-compose.yml)
services:
  otel-collector:
    image: otel/opentelemetry-collector-contrib:0.98.0
    restart: always
    command:
      - "--config=/etc/otel-collector-config.yaml"
    volumes:
      - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
    ports:
      - "8888:8888" # Prometheus metrics exposed by the collector
      - "8889:8889" # Prometheus exporter metrics
      - "4317:4317" # OTLP gRPC receiver
      - "4318:4318" # OTLP gRPC receiver
    depends_on:
      - jaeger
      - prometheus
      - tempo
      - loki

  jaeger:
    image: jaegertracing/all-in-one:latest
    restart: always
    ports:
      - "16686:16686" # UI
      - "14268" # ??
      - "14250" # ??

  tempo:
    image: grafana/tempo:2.4.1
    command:
      - '-config.file=/etc/tempo/config.yaml'
    volumes:
      - ./tempo.yaml:/etc/tempo/config.yaml
    ports:
      - 4318
      - 7999:7999

  prometheus:
    image: prom/prometheus:latest
    restart: always
    command:
      - '--config.file=/etc/prometheus/prometheus.yaml'
      - '--web.enable-remote-write-receiver'
    volumes:
      - ./prometheus.yaml:/etc/prometheus/prometheus.yaml
    ports:
      - "9090:9090"

  grafana:
    image: grafana/grafana:10.4.2
    ports:
      - 5050:3000
    volumes:
      - ./grafana.yaml:/etc/grafana/provisioning/datasources/datasources.yaml
    environment:
      - GF_AUTH_ANONYMOUS_ENABLED=true
      - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
      - GF_AUTH_DISABLE_LOGIN_FORM=true
    depends_on:
      - prometheus
      - tempo

  loki:
    image: grafana/loki:2.9.8
    command:
      - '-config.file=/etc/loki/config.yaml'
    volumes:
      - ./loki.yaml:/etc/loki/config.yaml
    ports:
      - 3100:3100

File: README.md

What is Spin?

Spin is an open source framework for building and running fast, secure, and
composable cloud microservices with WebAssembly. It aims to be the easiest way
to get started with WebAssembly microservices, and takes advantage of the latest
developments in the
WebAssembly component model
and Wasmtime runtime.

Spin offers a simple CLI that helps you create, distribute, and execute
applications, and in the next sections we will learn more about Spin
applications and how to get started.

Getting started

See the Install Spin page of the Spin documentation for a detailed
guide on installing and configuring Spin, but in short run the following commands:

bash
curl -fsSL https://spinframework.dev/downloads/install.sh | bash
sudo mv ./spin /usr/local/bin/spin

Alternatively, you could build Spin from source.

To get started writing apps, follow the quickstart guide,
and then follow the
Rust, JavaScript, Python, or Go
language guides, and the guide on writing Spin applications.

Language support

WebAssembly is a language-agnostic runtime: you can build WebAssembly components from a variety of source languages. Spin SDKs are available for several languages, including:

The Spin framework team supports the JavaScript, Rust, Go, and Python SDKs. Other language integrations are supported by their authors, and we're grateful to them for their work!

Usage

Below is an example of using the spin CLI to create a new Spin application. To run the example you will need to install the wasm32-wasip2 target for Rust.

bash
$ rustup target add wasm32-wasip2

First, run the spin new command to create a Spin application from a template.

bash
# Create a new Spin application named 'hello-rust' based on the Rust http template, accepting all defaults
$ spin new --accept-defaults -t http-rust hello-rust

Running the spin new command created a hello-rust directory with all the necessary files for your application. Change to the hello-rust directory and build the application with spin build, then run it locally with spin up:

bash
# Compile to Wasm by executing the `build` command.
$ spin build
Executing the build command for component hello-rust: cargo build --target wasm32-wasip2 --release
    Finished release [optimized] target(s) in 0.03s
Successfully ran the build command for the Spin components.

# Run the application locally.
$ spin up
Logging component stdio to ".spin/logs/"

Serving http://127.0.0.1:3000
Available Routes:
  hello-rust: http://127.0.0.1:3000 (wildcard)

That's it! Now that the application is running, use your browser or cURL in another shell to try it out:

bash
# Send a request to the application.
$ curl -i 127.0.0.1:3000
HTTP/1.1 200 OK
content-type: text/plain
transfer-encoding: chunked
date: Sun, 02 Mar 2025 20:09:11 GMT

Hello World!

You can make the app do more by editting the src/lib.rs file in the hello-rust directory using your favorite editor or IDE. To learn more about writing Spin applications see Writing Applications in the Spin documentation. To learn how to publish and distribute your application see the Publishing and Distribution guide in the Spin documentation.

Language Support for Spin Features

The table below summarizes the feature support in each of the language SDKs.

Feature Rust SDK Supported? TypeScript SDK Supported? Python SDK Supported? Tiny Go SDK Supported? C# SDK Supported?
Triggers
HTTP Supported Supported Supported Supported Supported
Redis Supported Supported Supported Supported Not Supported
APIs
Outbound HTTP Supported Supported Supported Supported Supported
Configuration Variables Supported Supported Supported Supported Supported
Key Value Storage Supported Supported Supported Supported Not Supported
SQLite Storage Supported Supported Supported Supported Not Supported
MySQL Supported Supported Not Supported Supported Not Supported
PostgreSQL Supported Supported Not Supported Supported Supported
Outbound Redis Supported Supported Supported Supported Supported
Serverless AI Supported Supported Supported Supported Not Supported
Extensibility
Authoring Custom Triggers Supported Not Supported Not Supported Not Supported Not Supported

Getting Involved and Contributing

We are delighted that you are interested in making Spin better! Thank you!

Each Monday at 9:00pm UTC, we meet to discuss Spin issues, roadmap, and ideas in our Spin Project Meetings. Demos are welcome. Link to the meeting can be found in the Spin Project Meeting agenda below.
If this meeting time does not work for you, please propose a one-off meeting at a different time or a new recurring time in the Spin Slack Channel or in the issue queue. We will do our best to accommodate.

The Spin Project Meeting agenda is a public document. The document contains a rolling agenda with the date and time of each meeting, the Zoom link, and topics of discussion for the day. You will also find the meeting minutes for each meeting and the link to the recording. If you have something you would like to demo or discuss at the project meeting, we encourage you to add it to the agenda.

You can find the contributing guide here.

Stay in Touch

Follow us on Twitter: @spinframework

You can join the Spin community in the Spin CNCF Slack channel where you can ask questions, get help, and show off the cool things you are doing with Spin!


File: crates/test-codegen-macro/README.md

Test Codegen Macro

A macro for automatically producing #[test] annotated functions based on file directory structure. This is used by the runtime tests so that when adding a runtime test, you're not required to also add a test function corresponding to that runtime test.


File: crates/componentize/adapters/README.md

Adapters

The componentize process uses adapters to adapt plain wasm modules to wasi preview 2 compatible wasm components. There are three adapters that are built and stored as wasm binaries in this repository:

  • The upstream wasi preview1 adapters for both commands and reactors for use with newer versions of wit-bindgen (v0.5 and above).
  • A modified adapter that has knowledge of Spin APIs for use with v0.2 of wit-bindgen which has a different ABI than newer wit-bindgen based modules.
    • This is currently built using commit 603fb3e on the github.com/rylev/wasmtime fork of wasmtime.
    • You can see a diff between the upstream wasmtime 18.0.1 compatible adapter and this custom adapter here.

File: crates/componentize/README.md

spin-componentize

This library converts a Spin module to a
component.

Note that although the world specifies both inbound-redis and inbound-http
exports, spin-componentize will only export either or both according to what
the original module exported.

Building

This crate requires a Rust installation v1.68 or later and a couple of Wasm targets:

shell
rustup target add wasm32-wasip1
rustup target add wasm32-unknown-unknown

Note that this is currently only a library and does not yet have a CLI interface, although that
would be easy to add if desired.

Testing

To test whether the spin componentize process produces wasm components that can be used with wasmtime, we run "abi conformance" testing. These tests are run with a plain cargo test invocation.

Wit and Adapters

spin-componentize and the abi conformance tests use component adapters built from wasmtime.

See the adapters README for more information.


File: cross/README.md

Polyfill for missing SIMD intrinsics in `cross-rs` image for target `aarch64-unknown-linux-musl`

A transitive dependency of spin (llama.cpp via ggml) uses the vld1q_s8_x4 and vld1q_u8_x4 compiler built-in SIMD intrinsics.
These intrinsics are missing for aarch64 in gcc < 10.3, while cross-rs ships with gcc 9 for aarch64-unknown-linux-musl as of writing.

The code in this folder does a feature check and patches the arm_neon.h header with polyfills if the functions are missing.

See https://github.com/spinframework/spin/issues/1786 for the upstream issue.


File: deploy/README.md

Deployments

The Spin Docs website is deployed via the deploy-website.yaml GitHub workflow.

(Note: currently this website consists of redirects to the Spin Docs hosted at spinframework.dev)

Auto Deploys

The production version of the website is deployed whenever commits are pushed to the main branch.

Manual Deploys

Deployments may also be triggered manually, providing a choice of ref and sha.

Nomad jobs

We currently deploy the website via its Nomad job directly. (In the future, we envision running the website as a Fermyon Cloud app.)

The spin-docs Nomad job contains configuration for the running website, including the OCI reference to run from.


File: docs/content/sips/001-spin-deploy.md

title = "SIP 001 - Spin Deploy" template = "main" date = "2022-03-18T14:53:30Z"

Summary: A Spin CLI command that will deploy a Spin application to the cloud

Owner: [email protected]

Created: March 18, 2022

Updated: March 31, 2022

Background

A Spin application โ€” (currently described as a spin.toml file) โ€” is a collection of one or more components, each invoked as a result of an event generated by a trigger. The Spin CLI currently enables running a Spin application locally via the spin up command. The Spin CLI also offers a set of commands enabling users to package and push a Spin application to a Bindle registry.

Hippo is a self-hosted, open source, Web Assembly PaaS that allows users to deploy and scale Web Assembly applications. Hippo takes a reference to a bindle, deploys it to the cloud and makes it publicly available. Hippo currently only works with Wagi applications and can currently deploy Wagi applications on a Nomad cluster with Traefik for routing. Additionally, Hippo has a concept called โ€œchannelsโ€ enabling users to track different version categories of an application (ex. alpha, beta, stable, pre-releases, minor versions, etc.).

A desired feature is to be able to deploy a Spin application to the cloud using Hippo so that it is accessible via a publicly available domain or IP address.

Proposal

Create a spin deploy command. This command packages a Spin application as a bindle, pushes it to a bindle registry and instructs Hippo to deploy the application to the cloud.

Configuration

This command needs the following configuration to be passed via either flags or environment variables or config file (config file to be defined at a later date) to deploy the application properly and to the right place:

  • Bindle server information
    • Environment variable: BINDLE_SERVER_URL
    • Flag: --bindle-server
  • Hippo URL information
    • Environment variable: HIPPO_URL
    • Flag: --hippo-url

Authentication with Hippo

Hippo authentication information. A token is needed to communicate with the Hippo server. This can be
retrieved either from requesting it from the Hippo server with a username and password, from the Hippo config file on the system (if a user has already logged in) or from the user if they already know the
token information. The following flags and environment variables support authenticating with Hippo.

  • Hippo token
    • Environment variable: HIPPO_TOKEN
    • Flag: --hippo-token
  • Hippo username
    • Environment variable: HIPPO_USERNAME
    • Flag: --hippo-username
  • Hippo password
    • Environment variable: HIPPO_PASSWORD
    • Flag: --hippo-password

The --hippo-token flag cannot be set in combination with the --hippo-username and --hippo-password flags. If so, Spin will return an error. If the username/password flags are set, Spin will request a token from the Hippo server and use it. If the username flag was provided but the password was not, Spin will prompt the user for a password. If none of the Hippo auth flags are provided, Spin will find the Hippo token in the Hippo config file on disk. If Hippo cannot find the file or the token in the file is expired, Spin will prompt the user for username/password.

Flow

As part of the deploy flow, Spin will:

  1. Create and push a bindle for the Spin app
  2. Create a Hippo app with the name given in the Spin.toml file. If app exists, it will use the existing app's ID for the next step. Note: Should we even be re-using an app? or should we create a unique app per deploy? I'm leaning towards the latter?
  3. Create a Hippo channel called "spin-deploy" (might be something we should allow for configuration via a flag). If the channel already exists, ensure that revision information is configured to pick up the new bindle version.
  4. Register a revision with Hippo so that the relevant channel(s) deploy the application.

Pre-requsites

In order to use the spin deploy command, a user must already have Hippo installed and running using the nomad scheduler and a bindle url.

Bindle versioning

A bindle is immutable once pushed and the tag cannot be overwritten. Therefore, we'll need a way to construct unique tags. One way to do this is to hash the bindle invoice that is generated.
Note: I believe Hippo only allows semver versions though and in that case, this would not work or we'd need to see if we can make Hippo pick up non-semver bindle tags.

Assumptions about the Hippo Platform

The following is a list of assumptions we are making about the Hippo platform that we would need to build in order for this command to work.

  • There needs to be a single endpoint on the Hippo API Server that takes the Spin application information and creates a Hippo application with a default channel configured to watch the correct bindle reference. See hippo-cli issue #97.
  • Hippo needs to support running Spin applications and not only Wagi applications. See hippo issue #579.

Additional Consideration: Plugin Model

In the future, we should make this command a plugin for the Spin CLI. People may not want to use the Spin deploy command to deploy to Hippo. They may want to deploy to a different target using a different platform. They should be able to do that via plugins. However, there is no plugin system in Spin at this time and that may require further debate and discussion and consideration, so it's best to continue with spin deploy as a built-in subcommand for the time being to be focused about the scope of work.


File: docs/content/sips/002-app-config.md

title = "SIP 002 - Application Configuration" template = "main" date = "2022-03-22T14:53:30Z"

Summary: A configuration system for Spin applications.

Owner: [email protected]

Created: March 22, 2022

Updated: July 19, 2022

Background

It is common for applications to require configuration at runtime that isn't known at build time or is too sensitive to be stored with build artifacts:

  • Logging configuration
  • Per-channel (production, staging, etc) service dependency URLs
  • Database secrets

Proposal

Configuration schema is defined by components and applications

Configuration within a "parent" (component or application) consists of a number of configuration "slots":

  • Slots are identified by a string "key"; in order to allow unambiguous conversion to environment variables or file paths, keys are constrained:
    • Keys must start with a letter (required for env vars)
    • Keys consist of only lowercase ascii alphanum and _ ([a-z0-9_])
      • Only one _ at a time and not at the end (to allow delimiting in env vars with __)
  • Slot keys must be unique within their parent, but to allow independent development of components different parents may have identical keys
  • A slot must either be marked as "required" or must be given a default value
  • A slot may be marked as "secret", in which case any associated value should be handled with care (e.g. not logged)
toml
[variables]
required_key = { required = true }
optional_key = { default = "default_value" }
secret_key = { required = true, secret = true }

Default values can use template strings to reference other slots.

toml
[variables]
key1 = { required = true }
key2 = { default = "prefix-{{ key1 }}-suffix" }

Components and applications set configuration values of their dependencies

In dependency configuration, templates strings can reference top-level config keys (those in [variables]), "sibling" keys within the same dependency, and "ancestor" dependant configs.

  • Top-level references use just the key name: {{ top_level_key }}
  • "Sibling" references use a single . prefix: {{ .sibling_key }}
  • "Ancestor" references use multiple .s: {{ ..parent_dep_key }}, {{ ...grandparent_key }}
  • Circular / infinitely recursive references are not permitted

spin.toml:

toml
[variables]
app_root = { default = "/app" }
log_file = { default = "{{ app_root }}/log.txt" }
...
[[component.config]]
work_root = "{{ app_root }}/work"      # -> "/app/work"
work_out = "{{ .work_root }}/output"   # -> "/app/work/output"
[[component.dependencies.dep1.config]]
dep_root = "{{ ..work_root }}/dep"     # -> "/app/work/dep"

Configuration "providers" resolve application configuration

When resolving the value of an application configuration slot, providers will be queried in-order for a value. If no value is returned by any provider, the resolution will either use the default value or fail (if the slot is "required").

Provider configuration is handled by spin at instantiation time (spin up).

Note: Provider configuration is TBD; as TOML it could look like:

toml
[[config-provider]]
type = "json_file"
path = "config.json"

[[config-provider]]
type = "env"
prefix = "MY_APP_"

Example providers

  • Environment provider
    • Configured with a prefix, e.g. SPIN_CONFIG_
    • key_one -> SPIN_CONFIG_KEY_ONE
  • File provider
    json
    {"key_one": "value-one"}
  • Vault provider

Configuration is exposed via component interface

spin-config.wit

text
// Unknown key is a runtime error
get-config: function(key: string) -> expect<string>
  • Since each component gets its own instance of the spin-config import, the executor can resolve keys automatically and only expose a component's own config to it.

Future design options

This section contains possible future features which are not fully defined here.

Typed configuration

The above assumes only string values, but we could include some typing:

toml
# Type can be inferred from default value:
number_key = { default = 123 }
# equivalent to:
number_key = { type = "number", default = 123 }

required_string = { type = "string", required = true }
# "bytes" would require e.g. base64 encoding in some places
encryption_key = { type = "bytes", required = true, secret = true}

WASI "configfs"

For languages without component support, we could expose config as synthetic mounted files:

ruby
key1_value = File.read("/config/key1")

# Typed config; `.json` encodes values to JSON
key1_value = JSON.parse(File.read("/config/key1.json"))

# "bytes" type; `.raw` decodes from base64
encryption_key = File.read("/config/encryption_key.raw")

File: docs/content/sips/003-trigger-executors.md

title = "SIP 003 - Trigger Executors" template = "main" date = "2022-04-29T14:53:30Z"

Summary: A new architecture for Spin trigger executors.

Owner: [email protected]

Created: April 29, 2022

Updated: May 5, 2022

Background

Spin currently includes built-in implementations for two trigger types: HTTP, and Redis (PubSub).
We want to allow for additional trigger types in the future, whether they are "internal" types developed and
supported within the Spin codebase, or "external" types developed by the broader community.

While it is currently possible to build external trigger types - as in the
TimerTrigger example - it requires replicating much of the
functionality provided by the spin up command.

Proposal

Trigger types are implemented as "trigger executors"

These executors are regular subcommands/binaries, but are not normally executed directly by
users.

  • "Internal" triggers use spin subcommands, e.g. spin trigger http
  • "External" triggers use external binaries, e.g. spin-trigger-timer
  • Trigger executors share common code, including common CLI options in a spin-trigger crate

The `spin up` command changes

It remains the primary entrypoint for starting a Spin app, but its behavior is changed to:

  1. Load the application manifest
  2. Find a trigger executor for the application (e.g. check the PATH for "spin-trigger-${trigger.type}")
  3. Set some environment variables:
    • SPIN_MANIFEST_URL: a URL pointing to the application manifest (e.g. file:///path/to/spin.toml or bindle+https://bindle-server?id=bindle-id)
    • SPIN_TRIGGER_TYPE the spin trigger type (e.g. http) being executed
  4. exec the trigger executor, forwarding its own CLI arguments

Future design options

This section contains possible future features which are not fully defined here.

Multi-trigger orchestration

If multiple trigger types were to be supported by a single application, the role of spin up could
grow to include trigger orchestration:

  • Finding executors for all required trigger types
  • Forking a child process for each trigger executor
  • Managing the child processes (restarts, graceful shutdowns, etc.)

Potential disadvantages

If the "Multi-trigger orchestration" option is taken, having separate processes for different triggers
might have some disadvantages:

  • Multiple triggers types would use more system resources implemented as multiple processes rather than as
    multiple async tasks in the same process, especially if a single module implements multiple trigger type
    handlers.
  • There has been discussion the possibility of trigger handlers making optimized "in-memory" calls to
    other triggers. This design would make cross-trigger-type calls of this sort more complex at best.