Spin Application Manifest Reference

This page describes the contents of the Spin manifest file, typically called spin.toml.

There are two versions of the manifest format. The manifest format described here (version 2) is recommended if you’re using Spin 2.0 and above. The previous format (version 1) is supported on Spin 2.x for backward compatibility, and is the only format supported by Spin 1.x.

Manifest Format

The manifest is a TOML file, and follows standard TOML syntax. See the TOML documentation for information about the TOML syntax. Here is an example Spin application manifest (spin.toml) that was generated using spin new -t http-rust spin-manifest-example-in-rust:

spin_manifest_version = 2

[application]
name = "spin-manifest-example-in-rust"
version = "0.1.0"
authors = ["Fermyon Engineering <engineering@fermyon.com>"]
description = "An example application to generate a Spin manifest file, in this case, via the HTTP Rust template."

[[trigger.http]]
route = "/..."
component = "spin-manifest-example-in-rust"

[component.spin-manifest-example-in-rust]
source = "target/wasm32-wasip1/release/spin_manifest_example_in_rust.wasm"
allowed_outbound_hosts = []
[component.spin-manifest-example-in-rust.build]
command = "cargo build --target wasm32-wasip1 --release"
watch = ["src/**/*.rs", "Cargo.toml"]

Using Variables in the Manifest

The following fields allow you to use expressions in their values:

  • application.trigger.redis.address
  • trigger.redis.address
  • trigger.redis.channel
  • component.*.allowed_outbound_hosts

Spin resolves manifest expressions at application load time. Subsequent changes to variables do not update expression-based values.

The only variables permitted in manifest expressions are application variables.

Manifest expressions are not yet supported on Fermyon Cloud.

Manifest Fields

NameRequired?TypeValueExample
spin_manifest_versionRequiredNumberThe version of the file format that the rest of the manifest follows. For manifests using this format, this value must be 2.2
applicationRequiredTableInformation about the application and application-global options. See The application Table below.[application]
name = "greetings"
version = "1.0.0"
variablesOptionalTableDynamic configuration variables which the user can set when they run the application. See The variables Table below.[variables]
message = { default = "hello" }
triggerRequiredTableAssociates triggers and conditions to the components that handle them - for example, mapping a HTTP route to a handling component. See The trigger Table below.[[trigger.http]]
component = "greeter"
route = "/greet"
componentRequiredTableThe WebAssembly components that make up the application, together with whatever configuration and resources they depend on, such as asset files or storage access. See The component Table below.[component.greeter]
source = "greeting_manager.wasm"
files = ["confetti.jpg"]

If you’re familiar with manifest version 1, note that the way trigger parameters map to components - for example, which component handles a particular HTTP route - is now defined on the trigger, not on the component. In the version 2 manifest, a component section specifies only the Wasm module and the resources it needs.

The application Table

NameRequired?TypeValueExample
nameRequiredStringThe name of the application. This may be any string of alphanumeric characters, hyphens and underscores."hello-world"
versionOptionalStringThe version of the application. The must be a string of the form major.minor.patch, where each element is a number."1.0.5"
descriptionOptionalStringA human-readable description of the application."The best app for all your world-greeting needs"
authorsOptionalArray of stringsThe authors of the applications. If present, this must ba an array, even if it has only one entry.["Jane Q Hacker (<dev@example.com>)"]
triggerOptionalTableApplication-global trigger settings. See The application.trigger Table below.[application.trigger.redis]
address = "redis.example.com"

The application.trigger Table

The application.trigger should contain only one key, the trigger type whose settings you want to override. This is usually written inline as part of the TOML table header, e.g. [application.trigger.redis].

In many cases, your trigger will have no settings, or the default ones will suffice. In this case, you can omit the application.trigger table.

The application.trigger.redis Table

NameRequired?TypeValueExample
addressRequiredStringThe address of the Redis instance to which the components subscribe for messages, for triggers that do not specify an address themselves. Use the redis: URL scheme."redis://localhost:6379"

The variables Table

The keys of the variables table are user-defined. The value of each key is another table with the fields shown in the following table.

Because each variables value usually contains only a few simple fields, you will usually see the table entries written inline with the values written using brace notation, rather than fully written out using square-brackets table syntax for each variable. For example:

[variables]
vessel = { default = "teapot" }
token = { required = true, secret = true }
NameRequired?TypeValueExample
defaultOptionalStringThe value of the variable if no value is supplied at runtime. If specified, the value must be a string. If not specified, required must be true."teapot"
requiredOptionalBooleanWhether a value must be supplied at runtime. If not specified, required defaults to false, and default must be providedfalse
secretOptionalBooleanIf set, this variable should be treated as sensitive.false

The trigger Table

The trigger table contains only one key, the trigger type to which your application responds. The value of this key is a table array. In practice, the trigger table is written using table array syntax with the trigger type inlined into each entry. For example:

[[trigger.http]]
route = "/users"
component = "user-manager"

[[trigger.http]]
route = "/reports"
component = "report"

Each array entry contains a mix of common fields and trigger-specific fields.

Common Fields for All trigger.(type) Tables

NameRequired?TypeValueExample
componentRequiredString or tableThe component to run when a trigger event matching the trigger setting occurs (for example, when Spin receives an HTTP request matching the trigger’s route). It can be in one of the following formats:
String* A key in the component table"user-manager"
Table* Specifies an unnamed component to be associated with the trigger setting. This allows simple components to be written inline instead of needing a separate section. Such a table follows the component table format.{ source = “reports.wasm” }`

Additional Fields for trigger.http Tables

NameRequired?TypeValueExample
routeRequiredString or tableThe route which this component handles. Requests to the route will cause the component to execute.
StringThis may be an exact route (/example), which matches only the given path, or may include wildcards (/example/:id or /example/...). If two routes overlap, requests are directed to the matching route with the longest prefix. See the HTTP trigger documentation for details and examples."/api/cart/..."
TableIf the component is a private endpoint used for local service chaining then use the table value shown here.{ private = true }
executorOptionalTableHow Spin should invoke the component. If present, this is a table. The type key is required and may have the values "spin" or "wagi". If omitted. the default is { type = "spin"}. See the HTTP trigger documentation for details.{ type = "wagi" }
If type = "spin" there are no other keys defined. In this case, Spin calls the component using a standard Wasm component interface. Components built using Spin SDKs or Spin interface files use this convention.{ type = "spin" }
If type = "wagi", Spin calls the component’s “main” (_start) function using a CGI-like interface. Components built using languages or toolchains that do not support Wasm interfaces will need to be called in this way. In this case, the following additional keys may be set:

* argv (optional): The string representation of the argv list that should be passed into the handler. ${SCRIPT_NAME} will be replaced with the script name, and ${ARGS} will be replaced with the query parameters of the request, formatted as arguments. The default is to follow the CGI specification, and pass ${SCRIPT_NAME} ${ARGS}

* entrypoint (optional): The name of the function to call as the entry point to this handler. By default, it is _start (which in most languages translates to main in the source code).

See the HTTP trigger documentation for details.
{ type = "wagi" }

Additional Fields for trigger.redis Tables

NameRequired?TypeValueExample
addressOptionalStringThe address of the Redis instance to which the trigger subscribes. Use the redis: URL scheme. If omitted, defaults to application.trigger.redis.address."redis://localhost:6379"
channelRequiredStringThe Redis channel which this component handles. Messages on this channel will cause the component to execute."purchases"

The component Table

The keys of the component table, usually written as part of the table syntax e.g. [component.my-component], are user-defined. (In the preceding example, the key is my-component). Component names must be kebab-cased, i.e. the only permitted separator is a hyphen.

The value of each key is a table with the following fields.

NameRequired?TypeValueExample
descriptionOptionalStringA human-readable description of the component."The shopping cart API"
sourceRequiredString or tableThe Wasm module which should handle the component. This must be built to work with the application trigger. It can be in one of the following formats:
String* The path to a Wasm file (relative to the manifest file)dist/cart.wasm
Table* The URL of a Wasm file downloadable over HTTP. This must be a table containing a url field for the Wasm file, and a digest field contains a SHA256 hex digest, used to check integrity.{ url = "https://example.com/example.wasm", digest = "sha256:6503...2375" }
Table (Highly Experimental)* The registry, package and version of a component from a registry. This experimental source configuration must be a table containing a registry domain field, a package field and a version field.{ registry = "registrytest-abcd.fermyon.app", package = "component:hello-world", version="0.0.1" } or { registry = "ttl.sh", package = "user:registrytest", version="1.0.0" }
filesOptionalArray of strings and/or tablesThe files to be made available to the Wasm module at runtime. This is an array, and each element of the array is either:[ "images/*.jpg", { source = "assets/images", destination = "/pictures" } ]
String* A file path or glob pattern, relative to the manifest file. The matching file or files will be available in the Wasm module at the same relative paths."images/*.jpg"
Table* A file or directory to be made available to the Wasm module at a specific path. This must be a table containing a source field for the file or directory relative to the manifest file, and a destination field containing the absolute path at which to make it available.{ source = "assets/images", destination = "/pictures" }
exclude_filesOptionalArray of stringsAny files or glob patterns that should not be available to the Wasm module at runtime, even though they match a files entry.[assets/images/test/**/*.*]
allowed_http_hostsOptionalArray of stringsThe host names or addresses to which the Wasm component is allowed to send HTTP requests. This is retained to simplify transition from the Version 1 manifest; new applications should use allow_outbound_hosts instead.["example.com", "localhost:8081"]
allowed_outbound_hostsOptionalArray of stringsThe addresses to which the Wasm component is allowed to send network requests. This applies to the outbound HTTP, outbound Redis, MySQL and PostgreSQL APIs. (It does not apply to built-in storage services such as key-value and SQLite.) Each entry must contain both a scheme, a name (or IP address) and a port in scheme://name:port format. For known schemes, you may omit the port if it is the default for the scheme. Use * for wildcards. If this field is omitted or an empty list, no outbound access is permitted.["mysql://db.example.com", "*://example.com:4567", "http://127.0.0.1:*"]
key_value_storesOptionalArray of stringsAn array of key-value stores that the Wasm module is allowed to read or write. A store named default is provided by the Spin runtime, though modules must still be permitted to access it. In current versions of Spin, "default" is the only store allowed.["default"]
environmentOptionalTableEnvironment variables to be set for the Wasm module. This is a table. The table keys are user-defined; the values must be strings.{ DB_URL = "mysql://spin:spin@localhost/dev" }
buildOptionalTableThe command that spin build uses to build this component. See The component.(id).build Table below.[component.cart.build]
command = "npm run build"
variablesOptionalTableDynamic configuration values to be made available to this component. The table keys are user-defined; the values must be strings, and may use template notation as described under Dynamic Configuration.[component.cart.variables]
api_base_url = "https://{{ api_host }}/v1"
dependencies_inherit_configurationOptionalBooleanIf true, dependencies can invoke Spin APIs with the same permissions as the main component. If false, dependencies have no permissions (e.g. network, key-value stores, SQLite databases). The default is false.false
dependenciesOptionalTableSpecifies how to satisfy Wasm Component Model imports of this component. See Using Component Dependencies.[component.cart.dependencies]
"example:calculator/adder" = { registry = "example.com", package = "example:adding-calculator", version = "1.0.0" }

If you’re familiar with manifest version 1, note that:

  • The component id is no longer a field within a [[component]], but the key of the component in the table, written as part of the [component.(id)] header.
  • The trigger association is no longer a [trigger] sub-table but is written in the separate trigger table.
  • The config section is now named variables.

The component.(id).build Table

NameRequired?TypeValueExample
commandRequiredStringThe command to execute on spin build."cargo build --target wasm32-wasip1 --release"
workdirOptionalStringThe directory in which to execute command, relative to the manifest file. The default is the directory containing the manifest file. An example of where this is needed is a multi-component application where each component is its own source tree in its own directory."my-project"
watchOptionalArray of stringsThe files or glob patterns which spin watch should monitor to determine if the component Wasm file needs to be rebuilt. These are relative to workdir, or to the directory containing the manifest file if workdir is not present.["src/**/*.rs", "Cargo.toml"]

Next Steps