Authoring Custom Spin Templates

Thorsten Hans headshot

May 06, 2025

Thorsten Hans

Thorsten Hans headshot

Written by

Thorsten Hans

Thorsten Hans is a Senior Developer Advocate at Akamai. He guides developers and teams through understanding, adopting, and mastering emerging technologies to build reliable software and embrace the next wave of cloud computing. As Docker Captain, he continues to share his experiments and knowledge with the developer community.

Share

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.

Thorsten Hans headshot

May 06, 2025

Thorsten Hans

Thorsten Hans headshot

Written by

Thorsten Hans

Thorsten Hans is a Senior Developer Advocate at Akamai. He guides developers and teams through understanding, adopting, and mastering emerging technologies to build reliable software and embrace the next wave of cloud computing. As Docker Captain, he continues to share his experiments and knowledge with the developer community.

Tags

Share

Related Blog Posts

Developers
Introducing Akamai Cloud Pulse: Observability for Your Cloud Infrastructure – Now in Open Beta
July 15, 2025
Akamai Cloud Pulse is now entering Open Beta for all Akamai Managed Database customers. Following successful closed beta testing, we are ready to provide you with real-time insights into your database performance and resource utilization.
Cloud
No Lag, All Frag: Level Up Your Gaming with Xonotic, K3s, and Edge Computing
March 20, 2025
Let’s set the scene for a gamer: you’re having the game of your life (and you wish you were streaming today of all days). You’re lining up the perfect Level up your gaming with Xonotic, K3s, and edge computing! Discover how to host a high-performance, low-latency game server using Akamai Cloud’s distributed compute regions. Say goodbye to lag and hello to seamless gameplay.
Cloud
An Inside Look at our Next Gen Object Storage Launch
August 28, 2025