In this article, we will explore how one could create custom templates for Spin. We will cover what Spin templates are, the benefits of creating custom templates, and you’ll be guided through the process of creating a custom template Spin and TinyGo.
What are Spin Templates?
Spin templates are pre-defined 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 Custom Templates For Spin?
Creating custom Spin templates can offer numerous advantages for both teams and individual developers. Here are some of the key reasons why you might want to develop your own templates:
- 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 resist 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 sub-folders that will be created on the users 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 use to add a component from this 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 pre-defined and custom template parameters to customize the content when stamping out a new application. See the following table listing all pre-defined 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 users 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 value (see the pattern
field).
Creating a Custom Spin Template
Now that we’ve covered a bunch of theory about Spin templates, let’s do some hands on and 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 over 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 he 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"]
With that, we finished our custom Spin template and could distributed 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 discover distributing a custom Spin template using a Git repository.
Your template(s) must resist 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.
As the template shown as part of this article, 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 to Dive Deeper
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 meet 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.