In this article, we will explore how to create custom templates for Spin. Read on to learn what Spin templates are, the benefits of creating custom templates, and how to create a custom template for Spin and TinyGo.
What are Spin templates?
Spin templates are predefined project scaffolds designed to help developers quickly set up new Spin projects.
These templates can contain boilerplate code, configuration files, and directory structures, providing a consistent starting point for specific types of applications.
By using custom Spin templates, developers can save time and ensure that their projects adhere to best practices and standards from the outset.
Why use custom templates for Spin?
Creating custom Spin templates can offer numerous advantages for both teams and individual developers. Choosing to develop your own templates can help you:
- Align with regulatory compliance: In certain industries, regulatory compliance is paramount. For instance, your IT security department may mandate the use of specific tools, frameworks, or dependencies. By creating custom Spin templates that incorporate these requirements, you can ensure that all new projects start off on the right foot, adhering to compliance standards from day one.
- Boost Sprint Zero performance: The initial phase of a project, often referred to as Sprint Zero, involves setting up the project’s infrastructure and initial codebase. Custom Spin templates can significantly speed up this process, particularly when working on similar projects, such as CRUD applications. By having a ready-made template, you can quickly create new projects with a consistent structure and configuration, allowing your team to focus on building features rather than setting up the basics.
- Maintain consistency across projects: Custom Spin templates help maintain consistency across multiple projects by ensuring that all projects start with the same base structure and configuration. This consistency makes it easier for team members to switch between projects and promotes best practices.
- Improve onboarding for new developers: Custom Spin templates can serve as a valuable onboarding tool for new developers. By providing a standard project setup, new team members can quickly get up to speed with the project’s structure and coding standards.
Characteristics of a Spin template
A Spin template consists of metadata and content files. Obviously, content files differ based on the desired programming language. Let’s have a look at the structure of the http-go template to understand where content and metadata files reside in a Spin template:
├── content
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ └── spin.toml
└── metadata
├── snippets
│ └── component.txt
└── spin-template.toml
The spin-template.toml file provides necessary information about the template and individual template parameter definitions.
The content folder contains those files and subfolders that will be created on the user’s disk when executing spin new.
Last but not least, the component.txt file in metadata/snippets adds support for the spin add command (which users can use to add a component from the template to an existing Spin application).
Parameters and filters for content files and snippets
Both content files and snippets use the Liquid template language. Consult the Liquid documentation to learn more about its syntax and language capabilities, such as control structures.
Spin templates make use of predefined and custom template parameters to customize the content when stamping out a new application. See the following table listing all predefined parameters that you could use within your content files and snippets:
Parameter Name |
Description |
project-name |
The name provided by the user as part of spin new or spin add |
output-path |
. for apps created with spin new. For spin add this will be the relative path to the source code |
authors |
Author information (pulled from the user’s git config or common environment variables like USER) |
On top of parameters, Spin defines custom filters for transforming variable values:
Filter Name |
Description |
kebab_case |
Transforms the input into kebab case (Hello World is turned into hello-world) |
snake_case |
Transforms the input into snake case (Hello World is turned into hello_world) |
pascal_case |
Transforms the input into Pascal case (Hello World is turned into HelloWorld) |
Custom template parameters
You can define custom template parameters using the parameters table in spin-template.toml . See the following fields that you can use when specifying a custom template parameter:
Field Name |
Required |
Description |
type |
Yes |
Desired data type. Supported values string |
prompt |
Yes |
The prompt that will be shown to the user as part of spin new or spin add |
default |
No |
The default value for this template parameter |
pattern |
No |
An optional RegEx for validating user input |
allowed_values |
No |
A list of valid options for the parameter. If specified, a select component will be rendered by spin CLI (format ["a", "b"]) |
For example, see the following custom template parameter definition for a fictive template parameter called json-indention:
[parameters]
json-indention = { type = "string", default = "2", pattern = "^(2|4)$", prompt = "JSON indention size" }
The json-indention parameter has a default value of 2. According to the regular expression, users can either provide 2 or 4 as the value (see the pattern field).
Creating a custom Spin template
Now that we’ve covered plenty of theory about Spin templates, let’s create a simple template that exposes data from a key-value store using an HTTP API in TinyGo.
In contrast to the default http-go templates, our new kv-go template will:
- Grant the Spin app permissions for using the default key-value store
- Use the Router provided by Spin SDK for Go
- Split application code into multiple .go files
Defining template metadata
We start by defining the template metadata (spin-template.toml). As part of this, we create two custom template parameters, allowing the user to tailor their new Spin application upon creation:
manifest_version = "1"
id = "kv-go"
description = "Key-Value data exposed via HTTP API using (Tiny)Go"
tags = ["key-value", "http", "api", "go"]
[add_component]
skip_files = ["spin.toml"]
[add_component.snippets]
component = "component.txt"
[parameters]
project-description = { type = "string", prompt = "Description", default = "" }
http-path = { type = "string", prompt = "HTTP path", default = "/...", pattern = "^/\\S*$" }
The template content files
Depending on the complexity of your custom Spin template, you may end up with many content files in your template. The following listings highlight the Spin manifest (spin.toml) and an extract from the actual source code provided as part of the template.
spin_manifest_version = 2
[application]
name = "{{project-name | kebab_case}}"
version = "0.1.0"
authors = ["{{authors}}"]
description = "{{project-description}}"
[[trigger.http]]
route = "{{http-path}}"
component = "{{project-name | kebab_case}}"
[component.{{project-name | kebab_case}}]
source = "main.wasm"
key_value_stores = ["default"]
[component.{{project-name | kebab_case}}.build]
command = "tinygo build -target=wasip1 -gc=leaking -buildmode=c-shared -no-debug -o main.wasm ."
watch = ["**/*.go", "go.mod"]
// main.go
package main
import (
"net/http"
spinhttp "github.com/fermyon/spin/sdk/go/v2/http"
)
func init() {
spinhttp.Handle(func(w http.ResponseWriter, r *http.Request) {
router := spinhttp.NewRouter()
router.GET("/keys", getKeys)
router.GET("/values/:key", getValueAtKey)
router.POST("/values/:key", setValueAtKey)
router.ServeHTTP(w, r)
})
}
// handlers.go
package main
import (
"encoding/json"
"fmt"
"net/http"
spinhttp "github.com/fermyon/spin/sdk/go/v2/http"
"github.com/fermyon/spin/sdk/go/v2/kv"
)
const storeName = "default"
type Payload struct {
Value string `json:"value"`
}
func getKeys(w http.ResponseWriter, req *http.Request, params spinhttp.Params) {
// see https://github.com/ThorstenHans/kv-go-template/blob/main/templates/kv-go/content/handlers.go
// ...
}
func getValueAtKey(w http.ResponseWriter, req *http.Request, params spinhttp.Params) {
// ...
}
func setValueAtKey(w http.ResponseWriter, req *http.Request, params spinhttp.Params) {
// ...
}
You can find all content files (such as .gitignore, go.mod, and go.sum) and the entire source code for this template in the sample repository on GitHub.
The spin add snippet
To add support for spin add, we have to provide a TOML snippet that will be injected into an existing spin.toml file when users execute spin add -t kv-go. As part of our template manifest (spin-template.toml), we set the path for the snippet to metadata/snippets/component.txt, create the file, and add the following content:
[[trigger.http]]
route = "{{http-path}}"
component = "{{project-name | kebab_case}}"
[component.{{project-name | kebab_case}}]
source = "{{ output-path }}/main.wasm"
key_value_stores = ["default"]
[component.{{project-name | kebab_case}}.build]
command = "tinygo build -target=wasip1 -gc=leaking -buildmode=c-shared -no-debug -o main.wasm ."
workdir = "{{ output-path }}"
watch = ["**/*.go", "go.mod"]
Now, we’ve finished our custom Spin template and can distribute it to make it discoverable for other Spin users.
How to distribute a custom Spin template
Distributing your custom template can be done through the following channels:
- Git repository
- Shared directory
- Tarball
For the sake of demonstration, let’s distribute a custom Spin template using a Git repository.
Your template(s) must reside in a templates folder located in the root of your repository, with each template in its own subdirectory.
When users install templates from your repository, Spin will, by default, look for a Git tag to identify a compatible version of the templates. This tag should be in the format spin/templates/vX.Y, where X is the major version and Y is the minor version of the user’s Spin installation. For example, if the user is on Spin 3.1.0, templates will be installed from spin/templates/v3.1. If this tag does not exist, Spin will install templates from HEAD.
To create a new public repository using the GitHub CLI (gh), you can follow these steps. This will automate the process of setting up the repository, adding all files from the current folder, committing the changes, and pushing them to GitHub:
# Initialize a Git repository
git init
# Add all files from the current folder (recursively)
git add .
# Commit the changes
git commit -m "feat(templates): Add kv-go template for Spin"
# Ensure you are authenticated with GitHub
gh auth login
# Create a new public repository
gh repo create REPOSITORY_NAME --public --source=.
# Push to the newly created repository
git push -u origin main
Replace REPOSITORY_NAME with the desired name for your new repository.
How to install a custom Spin template
Installing custom templates with Spin CLI is as easy as executing the spin templates install command and using the desired flags to tell Spin where it should install templates from.
Use the --git and the optional --branch flag for installing templates from Git repositories.
To install templates from a directory, specify the destination using the --dir flag.
Last but not least, use the --tar flag if you want to install Spin templates from a tarball.
Since our template has already been distributed using a public git repository, you can install it using the following command:
spin templates install --git thorstenhans/kv-go-template
Copying remote template source
Installing template kv-go...
Installed 1 template(s)
+------------------------------------------------------------+
| Name Description |
+============================================================+
| kv-go Key-Value data exposed via HTTP API using (Tiny)Go |
+------------------------------------------------------------+
With the kv-go template installed on your machine, you can create a new Spin app from the template, build it, and run it locally using the following commands:
# Create a new Spin App using the kv-go template
spin new -t kv-go -a hello-kv
# move into the application directory
cd hello-kv
# Build the Spin App
spin build
# Run the Spin App locally
spin up
From within a new terminal instance, you can send requests to your hello-kv app using a tool like curl:
curl -i localhost:3000/keys
HTTP/1.1 200 OK
content-type: application/json
content-length: 3
date: Thu, 22 May 2025 12:47:46 GMT
[]
Resources for a deeper dive
Here are some valuable resources to dive deeper into authoring, distributing, and installing Spin templates:
Conclusion
Creating custom Spin templates can improve your development process, making sure you follow rules and keep things consistent across all your projects. Whether you’re working with a team or on your own, custom templates are a valuable tool to increase productivity and project quality. Follow the steps provided in this post and check out the recommended resources to learn more about authoring and using custom templates for Spin.
Tags