Application Structure
A Spin application can contain multiple components. If more than one component is built from source, you should consider how to organise the application project.
If you have multiple components, but all except one is downloaded from a remote source such as a URL, you don’t need to worry about the additional structure recommended on this page here. For example, an application with one custom component and two fileserver components doesn’t need to start from the
empty
template.
The discussion on this page assumes that you know from the start that you are going to need to build multiple components. If you’ve already started a project, you may need to move some existing code around when you add your second built-from-source component. For information about this, see this Spin Application Structure blog post or this video.
The blog post and video show manifest changes in the Spin 1 format. In the Spin 2 manifest format, the changes are similar, affecting the component
source
andbuild
sections.
Recommended Application Structure
If we start with a blank canvas and use the http-empty
template we will get a new Spin application:
$ spin new -t http-empty
Enter a name for your new application: myapp
Description: My application
The above command will provide an empty structure, as shown below:
└── myapp
└── spin.toml
To add new components to the application, we simply move into the myapp
directory and begin to add components using the spin add
subcommand:
$ spin add -t http-rust
Enter a name for your new component: first-http-rust-component
Description: The first of many new components
HTTP path: /first/...
$ spin add -t http-rust
Enter a name for your new component: second-http-rust-component
Description: The second of many new components
HTTP path: /second/...
After adding two new components, we can see the visual representation of our application. Notice the symmetry; there is no hierarchy or nesting of components:
.
├── first-http-rust-component
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
├── second-http-rust-component
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
└── spin.toml
To customize each of the two components, we can modify the lib.rs
(Rust source code) of each component:
use spin_sdk::http::{IntoResponse, Request, Response};
use spin_sdk::http_component;
/// A simple Spin HTTP component.
#[http_component]
fn handle_first_http_rust_component(req: Request) -> anyhow::Result<impl IntoResponse> {
println!("Handling request to {:?}", req.header("spin-full-url"));
Ok(Response::builder()
.status(200)
.header("content-type", "text/plain")
.body("Hello, First Component")
.build())
}
#[http_component]
fn handle_second_http_rust_component(req: Request) -> anyhow::Result<impl IntoResponse> {
println!("Handling request to {:?}", req.header("spin-full-url"));
Ok(Response::builder()
.status(200)
.header("content-type", "text/plain")
.body("Hello, Second Component")
.build())
}
As an additional example of adding more components, let’s add a new static file server component:
$ spin add -t static-fileserver
Enter a name for your new component: assets
HTTP path: /static/...
Directory containing the files to serve: assets
After the static file server component is added, we create the assets
directory (our local directory containing the files to serve) and then add some static content into the assets
directory to be served:
$ mkdir assets
$ cp ~/Desktop/my-static-image.jpg assets
$ cp ~/Desktop/old.txt assets
$ cp ~/Desktop/new.txt assets
The above commands are just an example that assumes you have the image (
my-static-image.jpg
) and two text files (old.txt
&new.txt
) on your Desktop.
Why stop there? We can add even more functionality to our application. Let’s now add a redirect
component to redirect requests made to /static/old.txt
and forward those through to /static/new.txt
:
$ spin add -t redirect
Enter a name for your new component: additional-component-redirect
Redirect from: /static/old.txt
Redirect to: /static/new.txt
We now have 4 separate components scaffolded for us by Spin. Note the application manifest (the spin.toml
file) is correctly configured based on our spin add
commands:
spin_manifest_version = 2
[application]
name = "myapp"
version = "0.1.0"
[[trigger.http]]
route = "/first/..."
component = "first-http-rust-component"
[component.first-http-rust-component]
source = "first-http-rust-component/target/wasm32-wasip1/release/first_http_rust_component.wasm"
allowed_outbound_hosts = []
[component.first-http-rust-component.build]
command = "cargo build --target wasm32-wasip1 --release"
workdir = "first-http-rust-component"
watch = ["src/**/*.rs", "Cargo.toml"]
[[trigger.http]]
route = "/second/..."
component = "second-http-rust-component"
[component.second-http-rust-component]
source = "second-http-rust-component/target/wasm32-wasip1/release/second_http_rust_component.wasm"
allowed_outbound_hosts = []
[component.second-http-rust-component.build]
command = "cargo build --target wasm32-wasip1 --release"
workdir = "second-http-rust-component"
watch = ["src/**/*.rs", "Cargo.toml"]
[[trigger.http]]
route = "/static/..."
component = "assets"
[component.assets]
source = { url = "https://github.com/fermyon/spin-fileserver/releases/download/v0.1.0/spin_static_fs.wasm", digest = "sha256:96c76d9af86420b39eb6cd7be5550e3cb5d4cc4de572ce0fd1f6a29471536cb4" }
files = [ { source = "assets", destination = "/" } ]
[[trigger.http]]
component = "additional-component-redirect"
route = "/static/old.txt"
[component.additional-component-redirect]
source = { url = "https://github.com/fermyon/spin-redirect/releases/download/v0.1.0/redirect.wasm", digest = "sha256:8bee959843f28fef2a02164f5840477db81d350877e1c22cb524f41363468e52" }
environment = { DESTINATION = "/static/new.txt" }
Also, note that the application’s folder structure, scaffolded for us by Spin via the spin add commands, is symmetrical and shows no nesting of components:
├── assets
│ ├── my-static-image.jpg
│ ├── new.txt
│ └── old.txt
├── first-http-rust-component
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
├── second-http-rust-component
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
└── spin.toml
This is the recommended Spin application structure.
Next Steps
- Learn about how to build your Spin application code
- Try running your application locally
- Discover how Spin application authors design and organise applications
- Learn about how to configure your application at runtime
- Look up details in the application manifest reference
- Try deploying a Spin application to the Fermyon Cloud