Templates

Template anatomy

A template is a directory with a spin.toml manifest and a base/ tree. spin loads it, collects params, renders the tree, runs pre-hooks, writes the files, run...

Quick start

Create a template with spin init:

spin init my-cli-template

This writes:

my-cli-template/
  spin.toml          # manifest
  _base/             # file tree rendered into the project
    file.txt.tmpl
  README.md

Edit spin.toml and _base/ to taste, then test it:

spin new myapp ./my-cli-template --dry-run

Required files

spin.toml

The manifest declares metadata, params, hooks, and include rules.

name = "my-cli-template"
description = "A minimal CLI template"
version = "0.1.0"
type = "cli"
language = "go"
min_spin_version = "0.1.0"

[params]
project_name = { type = "text", prompt = "Project name", default = "myproject" }
license = { type = "license", prompt = "License", default = "MIT" }

[[pre]]
run = "mkdir -p cmd"

[[post]]
run = "echo 'Created {{ .project_name }}'"

_base/

Every file inside _base/ is copied into the user's project. Files ending in .tmpl are run through Go's text/template with the resolved param values. The .tmpl extension is stripped in the output.

_base/
  README.md.tmpl      # rendered as README.md
  go.mod.tmpl         # rendered as go.mod
  .gitignore          # copied verbatim

Optional files

_pre/

The _pre/ directory holds assets your [[pre]] hooks need. spin copies _pre/ verbatim into the generated project as _pre/ before the pre-hooks run, so the hooks can reference those files even though _base/ has not been written yet:

my-template/
  spin.toml
  _base/
  _pre/
    init.sh
[[pre]]
run = "bash _pre/init.sh"

_post/

The _post/ directory holds assets your [[post]] hooks need: setup scripts, binaries, patch files, etc. spin copies _post/ verbatim into the generated project as _post/ before running the post-hooks:

my-template/
  spin.toml
  _base/
  _post/
    setup.sh
[[post]]
run = "bash _post/setup.sh"

Asset directory notes

  • Files in _pre/ and _post/ are copied verbatim (.tmpl suffix is ignored).
  • Every file in _pre/ and _post/ is executed automatically as the last pre-hook and post-hook steps, sorted alphabetically.
  • Both directories remain in the generated project. Remove them in a hook if you do not want them in the final output.

Non-template files

Any file in _base/ without a .tmpl suffix is copied verbatim into the project.

Conditional files and directories

Use [[include]] rules in spin.toml to include whole files or directories only when a param is true. For example, include a .github/ directory only when the user opts into CI:

[params]
ci = { type = "bool", prompt = "Include CI?", default = true }

[[include]]
path = ".github/**"
if = "{{ .ci }}"

See the spin.toml reference for the full syntax.

What spin does not care about

The language, framework, build tool, test runner, and dependency manager are entirely up to the template author. spin only owns the load/prompt/render/hook pipeline.