Templates

Hooks

Hooks are shell commands declared in spin.toml. They are rendered through text/template with the resolved param values and run via sh -c in the generated pro...
  • [[pre]] runs after params are resolved but before files are rendered or written.
  • [[post]] runs after files are written but before the output spin.toml is removed.

Trust and safety

Every hook command is shown to you before it runs. When you open the hooks review screen (the second step of spin new), you see a scrollable list of every [[pre]] and [[post]] command the template will execute, including hook scripts from _pre/ and _post/. You can inspect them all and choose between:

  • Run — execute all hooks and scaffold the project
  • Skip — scaffold the project but skip all hooks
  • Cancel — do nothing, dismiss the dialog

No shell command runs without your review. This is intentional: spin treats every template as potentially untrusted and gives you full visibility before any code executes.

Spin also rejects any rendered file path that resolves outside the destination directory, protecting you from path traversal attacks in malicious templates.

Quick example

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

[[post]]
run = "go mod init {{ .project_name }}"

[[post]]
run = "git init && git add -A && git commit -m 'initial'"

Commands run in order. The first failure stops the hook chain.

Pre-hooks

Use pre-hooks to prepare the destination directory before files land. They can create directories, initialise package managers that need a project root, or write files that later .tmpl files can reference.

[[pre]]
run = "go mod init {{ .project_name }}"

If a pre-hook fails, no files are written and no post-hooks run.

Post-hooks

Use post-hooks to finish the project after files are written.

[[post]]
run = "go mod init {{ .project_name }}"

[[post]]
run = "git init && git add -A && git commit -m 'initial'"

If a post-hook fails, the rendered files remain on disk so you can inspect or fix the state.

Templating

Hook commands are rendered through text/template with the same param values used for file rendering, but only field access is available:

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

Custom functions like upper, quote, and snake_case are only available in _base/*.tmpl file templates, not in hook commands. If you need a transformed value in a hook, use shell tools:

[[post]]
run = "echo {{ .project_name }} | tr '[:lower:]' '[:upper:]'"

Hook scripts

For non-trivial hooks you can drop scripts in _pre/ and _post/ instead of inlining everything in spin.toml:

my-template/
  spin.toml
  _base/
  _pre/
    01-mkdir.sh
    02-init.sh
  _post/
    setup.sh
    cleanup.sh

spin runs every file in _pre/ and _post/ automatically as the last pre-hook and post-hook steps, sorted alphabetically. Inline [[pre]]/[[post]] commands and hook scripts can be used together.

  • Executable files are run as ./_pre/<file> or ./_post/<file>.
  • Non-executable files are run with sh.
  • Hidden files and subdirectories are ignored.

Skipping hooks

Pass --no-hooks to spin new to skip both [[pre]] and [[post]] hooks and hook scripts. Pass --verbose to print hook output.

Failure behavior

If a hook fails, spin reports the command and its combined output. Pre-hook failures stop before any files are written; post-hook failures leave the rendered files in place.