Template anatomy
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 (.tmplsuffix 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.