Building Spin Application Code

A Spin application is made up of one or more components. Components are binary Wasm modules; building refers to the process of converting your source code into those modules.

Even languages that don’t require a compile step when used ‘natively’ may still require a build step to adapt them to work as Wasm modules.

Because most compilers don’t target Wasm by default, building Wasm modules often requires special command options, which you may not have at your fingertips. What’s more, when developing a multi-component application, you may need to issue such commands for several components on each iteration. Doing this manually can be tedious and error-prone.

To make the build process easier, the spin build command allows you to build all the components in one command.

You don’t have to use spin build to manage your builds. If you prefer to use a Makefile or other build system, you can! spin build is just there to provide an ‘out of the box’ solution.

Setting Up for spin build

To use spin build, each component that you want to build must specify the command used to build it in spin.toml, as part of its component.(name).build table:

[component.hello]
# This is the section you need for `spin build`
[component.hello.build]
command = "npm run build"

If you generated the component from a Fermyon-supplied template, the build section should be set up correctly for you. You don’t need to change or add anything.

Different components may be built from different languages, and so each component can have its own build command. In addition, some components may be precompiled into Wasm modules, and don’t need a build command at all. If a component doesn’t have a build command, spin build just skips it.

For Rust applications, you must have the wasm32-wasip1 target installed:

$ rustup target add wasm32-wasip1

The build command typically runs cargo build with the wasm32-wasip1 target and the --release option:

[component.hello.build]
command = "cargo build --target wasm32-wasip1 --release"

If you are on Rust 1.77 or earlier, use wasm32-wasi (without the p1). We recommend upgrading to Rust 1.78 or above. Future versions of Rust will not support wasm32-wasi (without the p1).

For JavaScript and TypeScript applications, you must have Node.js.

It’s normally convenient to put the detailed build instructions in package.json. The build script looks like:

{
  "scripts": {
    "build": "npx webpack --mode=production && npx mkdirp target && npx j2w -i dist.js -d combined-wit -n combined -o target/spin-http-js.wasm"
  }
}
Parts of the build script

The build script calls out to webpack and j2w which is a script provided by the @fermyon/spin-sdk package that utilizes ComponentizeJS.

The build command can then call the NPM script:

[component.hello.build]
command = "npm run build"

Ensure that you have Python 3.10 or later installed on your system. You can check your Python version by running:

python3 --version

If you do not have Python 3.10 or later, you can install it by following the instructions here.

For Python applications, you must have componentize-py installed:

$ pip3 install componentize-py

The build command then calls componentize-py on your application file:

[component.hello.build]
command = "componentize-py -w spin-http componentize app -o app.wasm"

For Go applications, you must use the TinyGo compiler, as the standard Go compiler does not yet support the WASI standard. See the TinyGo installation guide.

The build command calls TinyGo with the WASI backend and appropriate options:

[component.hello.build]
command = "tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go"

The output of the build command must match the component’s source path. If you change the build or source attributes, make sure to keep them in sync.

Running spin build

Once the build commands are set up, running spin build will execute, sequentially, each build command:

$ spin build
Building component hello with `cargo build --target wasm32-wasip1 --release`
    Updating crates.io index
    Updating git repository `https://github.com/fermyon/spin`

    //--snip--

    Compiling hello v0.1.0 (hello)
    Finished release [optimized] target(s) in 39.05s
Finished building all Spin components

If your build doesn’t work, and your source code looks okay, you can run spin doctor to check for problems with your Spin configuration and tools.

Running the Application After Build

You can pass the --up option to spin build to start the application as soon as the build process completes successfully.

This is equivalent to running spin up immediately after spin build. It accepts all the same flags and options that up does. See Running Applications for details.

Overriding the Working Directory

By default, the command to build a component is executed in the directory containing the spin.toml file. If a component’s entire build source is under a subdirectory, it is often more convenient to build in that subdirectory rather than try to pass the path to the build command. You can do this by setting the workdir option in the component.(id).build table.

For example, consider this Rust component located in subdirectory deep:

.
├── deep
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
└── spin.toml

To have the Rust build command run in directory deep, we can set the component’s workdir:

[component.deep.build]
# `command` is the normal build command for this language
command = "cargo build --target wasm32-wasip1 --release"
# This tells Spin to run it in the directory of the build file (in this case Cargo.toml)
workdir = "deep"

workdir must be a relative path, and it is relative to the directory containing spin.toml. Specifying an absolute path leads to an error.

Next Steps