Templates are the core building blocks of the Boilerplates CLI. This page explains what templates are, how they work, and how to use them effectively.
A template is a directory-based configuration package that contains:
When you generate a template, the CLI:
Every template is a directory containing at minimum a template.yaml file:
template-name/
├── template.yaml # Template definition and metadata
├── docker-compose.yml.j2 # Jinja2 template files
├── .env.j2 # Environment configuration
└── README.md # Static file (copied as-is)
This file defines everything about your template:
---
kind: compose # Module type (compose, terraform, ansible, etc.)
schema: "X.Y" # Schema version (affects available features)
metadata:
name: My Service
description: Service description with Markdown support
version: 1.0.0 # Application/service version
author: Your Name
date: '2025-01-12'
tags:
- docker
- service
spec:
# Variable specifications (see Variables page)
Templates are organized in libraries. A library is a collection of templates for a specific module type.
~/.config/boilerplates/libraries/
└── default/
└── library/
├── compose/
│ ├── nginx/
│ ├── traefik/
│ └── whoami/
├── terraform/
└── ansible/
# List all templates for a module
boilerplates compose list
# Search templates by name
boilerplates compose search proxy
# Show details about a template
boilerplates compose show nginx
metadata:
name: Template Name # Display name
description: Description # What the template does
version: 1.0.0 # Application version
author: Your Name # Template author
date: '2025-01-12' # Last update date
metadata:
tags: # Searchable tags
- docker
- web-server
draft: false # Hide from listings if true
next_steps: | # Post-generation instructions
## What's Next
1. Review the generated files
2. Customize as needed
3. Deploy!
The description field supports Markdown:
metadata:
description: |
A **powerful reverse proxy** and load balancer.
## Features
- Automatic HTTPS
- Load balancing
- Let's Encrypt integration
## Resources
- **Project**: https://traefik.io
- **Documentation**: https://doc.traefik.io
This renders nicely when you run boilerplates compose show <template>.
Files ending in .j2 are processed by Jinja2:
docker-compose.yml.j2:
services:
{{ service_name }}:
image: nginx:{{ nginx_version }}
ports:
- "{{ nginx_port }}:80"
{% if enable_ssl %}
volumes:
- ./ssl:/etc/nginx/ssl
{% endif %}
After rendering with variables:
service_name=webnginx_version=1.25nginx_port=8080enable_ssl=trueGenerated docker-compose.yml:
services:
web:
image: nginx:1.25
ports:
- "8080:80"
volumes:
- ./ssl:/etc/nginx/ssl
Files without .j2 extension are copied as-is:
README.md - Copied unchangedscripts/setup.sh - Copied unchangedTemplates can include other template files:
main.j2:
{% include 'common/header.j2' %}
services:
{{ service_name }}:
image: nginx:latest
common/header.j2:
version: '3.8'
name: {{ project_name }}
Templates declare a schema version that determines available features:
schema: "X.Y" # Use schema version X.Y (e.g., "1.0", "1.2")
Why Schema Versions?
Checking Current Schema:
To find the latest schema version and available features for each module, refer to the module-specific variable documentation:
Each Variables page documents the current schema and which features are available.
boilerplates repo update # Sync libraries
boilerplates compose list # Discover templates
boilerplates compose show nginx
Shows:
# Interactive mode
boilerplates compose generate nginx
# Non-interactive mode
boilerplates compose generate nginx ./my-nginx \
--var service_name=my-nginx \
--no-interactive
# Validate template structure
boilerplates compose validate nginx
# Validate all templates
boilerplates compose validate
Templates are identified by their directory name:
library/compose/nginx/ → template ID: nginx
library/compose/traefik/ → template ID: traefik
When using multiple libraries, templates can have qualified IDs:
# Simple ID (uses first matching template from priority order)
boilerplates compose generate nginx
# Qualified ID (targets specific library)
boilerplates compose generate nginx.local
boilerplates compose generate nginx.default
Templates inherit variables from module specifications. You only need to override what's different.
Module spec defines:
service_name (default: empty)container_port (default: 8080)restart_policy (default: unless-stopped)Template overrides:
spec:
general:
vars:
service_name:
default: nginx # Override default
# container_port inherits 8080
# restart_policy inherits unless-stopped
This keeps templates concise—you only specify what's unique.
my-service, nginx-proxy)docker-compose.yml.j2, not dc.j2)Application Versions:
image: nginx:1.25.3metadata.version to match applicationTemplate Updates:
metadata.version when updatingmetadata.date to current datedescriptionnext_steps for post-generation instructionsBefore publishing:
# Validate template
boilerplates compose validate my-template
# Test generation (dry run)
boilerplates compose generate my-template --dry-run
# Test with real generation
boilerplates compose generate my-template /tmp/test
# Verify generated files
cd /tmp/test && docker compose config
Use Jinja2 conditionals to skip entire sections:
{% if traefik_enabled %}
labels:
- "traefik.enable=true"
- "traefik.http.routers.{{ service_name }}.rule=Host(`{{ traefik_host }}`)"
{% endif %}
Template file names can use variables (though this is rare):
config-{{ environment }}.yml.j2 # Generates: config-prod.yml
Templates are validated on load: