A powerful tool for customizing project templates using comment-based markers while keeping templates fully functional and compileable.
Template Customizer transforms project templates into customized, ready-to-use projects by replacing marker comments with configuration values. Unlike traditional templating tools that break your code with placeholder variables, Template Customizer uses comments to mark customization points, keeping your templates fully functional during development.
β
Templates Stay Functional - Your template code runs and compiles during development
β
IDE-Friendly - No syntax errors from placeholder variables
β
Version Control Friendly - Clean diffs, reviewable code
β
Multi-Language Support - Works with Python, JavaScript, YAML, Docker, and more
β
Safe Processing - Dry-run mode, automatic backups, validation
β
Clear Warnings - Missing configuration values are clearly reported
Before (template file):
# app_name = {{ values.project.name | quote }}
app_name = "DefaultApp"
# port = {{ values.server.port }}
port = 3000Configuration (config.yml):
project:
name: "MyAwesomeApp"
server:
port: 8080After (customized file):
# app_name = {{ values.project.name | quote }}
app_name = "MyAwesomeApp"
# port = {{ values.server.port }}
port = 8080The comment markers are preserved, and only the values are updated!
Install Template Customizer with a single command:
# Install to /usr/local/bin (requires sudo)
curl -fsSL https://github.com/mkuhl/customizer/releases/latest/download/install.sh | sh
# Install to custom directory (no sudo needed)
curl -fsSL https://github.com/mkuhl/customizer/releases/latest/download/install.sh | sh -s -- --dir ~/.local/bin
# Use immediately (startup time ~100ms)
customizer --version
customizer process --dry-runIf you prefer manual installation:
# Download and extract the native Linux binary
curl -L https://github.com/mkuhl/customizer/releases/latest/download/customizer-linux-x64.tar.gz | tar xz
# Move to system path
sudo mv customizer /usr/local/bin/
# Use immediately
customizer --version
customizer process --dry-runFor cross-platform compatibility or when native binary isn't available:
# Download the Docker wrapper script
curl -L -o run-docker-customizer.sh https://github.com/mkuhl/customizer/releases/latest/download/run-docker-customizer.sh
chmod +x run-docker-customizer.sh
sudo mv run-docker-customizer.sh /usr/local/bin/
# Verify installation
run-docker-customizer.sh --versionπ Complete Docker Documentation - Detailed Docker usage, CI/CD integration, and troubleshooting
| Method | Startup Time | Size | Requirements | Best For |
|---|---|---|---|---|
| One-Liner Install | ~100ms β‘ | 11MB | Linux x86_64, GLIBC 2.31+ | Easiest setup, recommended for most users |
| Manual Binary | ~100ms β‘ | 11MB | Linux x86_64, GLIBC 2.31+ | CI/CD pipelines, controlled environments |
| Docker Methods | 2-3s | N/A | Docker installed | Cross-platform consistency, CI/CD integration |
For Native Binary:
- Linux x86_64 (Ubuntu 20.04+, RHEL 8+, Debian 11+, or compatible)
- GLIBC 2.31 or newer (check with
ldd --version)
For Docker Methods:
- Docker installed and running
- See Docker Documentation for detailed requirements
- Add markers to your template files:
# app_name = {{ values.project.name | quote }}
app_name = "DefaultApp"
# version = {{ values.project.version | quote }}
version = "0.1.0"- Create a configuration file:
# config.yml
project:
name: "MyAwesome App"
version: "1.2.0"
description: "Built from template"- Customize your template:
# Preview changes
customizer process --project ./my-template --config ./config.yml --dry-run
# Apply changes
customizer process --project ./my-template --config ./config.yml --yesFor Docker usage examples, see the Docker Documentation.
Filter files by pattern:
# Only process Python and JavaScript files
customizer process --project ./template --config ./config.yml --include "*.py,*.js" --dry-run
# Exclude test files
customizer process --project ./template --config ./config.yml --exclude "*test*,*spec*" --dry-runVerbose output with warnings:
# See detailed processing information and missing value warnings
customizer process --project ./template --config ./config.yml --verbose --dry-runBatch processing:
# Process without interactive prompts
customizer process --project ./template --config ./config.yml --yes- π Project Scaffolding - Initialize new projects from company templates
- π§ Environment Configuration - Deploy same codebase to dev/staging/prod
- π’ Multi-Tenant Applications - Configure for different clients/tenants
- π³ Docker Deployments - Customize compose files for different environments
- π¦ Package Templates - Create npm/pip packages with correct metadata
- βοΈ CI/CD Pipelines - Generate environment-specific configurations
- Comment-based markers - Templates remain fully functional and compileable
- External replacements - JSONPath for JSON files, patterns for Markdown (no comments needed!)
- Multi-language support - Python, JavaScript, TypeScript, YAML, HTML, CSS, Docker, and more
- Rich CLI output - Progress bars, colored output, and detailed previews
- Dry-run mode - Preview changes before applying
- Safe processing - Automatic backups and validation
- Missing value warnings - Clear warnings for undefined configuration values
- Flexible filtering - Include/exclude patterns for selective processing
- Docker support - Complete Docker integration for CI/CD and cross-platform deployment
Template markers use comment syntax that preserves functionality:
# variable_name = {{ jinja2_expression }}
actual_value = "default_value"Supported file types and comment syntax:
- Python/Shell:
# marker = {{ expr }} - JavaScript/TypeScript:
// marker = {{ expr }} - CSS/SCSS:
/* marker = {{ expr }} */ - HTML/XML:
<!-- marker = {{ expr }} --> - YAML:
# marker = {{ expr }} - Dockerfile:
# marker = {{ expr }}
The tool will:
- Find the comment line with the marker
- Render the Jinja2 expression using your config values
- Replace the following line with the rendered result
- Preserve the comment line unchanged
Configuration files support both YAML and JSON formats with nested structure:
project:
name: "MyApp"
version: "1.0.0"
description: "My application"
database:
host: "localhost"
port: 5432
features:
auth_enabled: true
metrics_enabled: false
docker:
registry: "ghcr.io"
image_name: "myapp"Access nested values in templates using dot notation:
# db_host = {{ values.database.host | quote }}
db_host = "localhost"
# app_name = {{ values.project.name | quote }}
app_name = "MyApp"
# port = {{ values.database.port }}
port = 5432
# registry = {{ values.docker.registry | quote }}
registry = "ghcr.io"Template Customizer now supports self-referencing configuration values, allowing you to build complex configurations from simpler values and eliminate duplication:
# config.yml
project:
name: "my-microservice"
version: "1.2.0"
environment: "production"
# Reference other values in the same configuration
docker:
registry: "ghcr.io/mycompany"
image: "{{ values.docker.registry }}/{{ values.project.name }}:{{ values.project.version }}"
database:
name: "{{ values.project.name | replace('-', '_') }}_{{ values.project.environment }}"
host: "{{ values.project.name }}-{{ values.project.environment }}.cluster.amazonaws.com"
api:
base_url: "https://{{ values.project.name }}.{{ values.project.environment }}.mycompany.com"
health_check: "{{ values.api.base_url }}/health"
monitoring:
namespace: "{{ values.project.name }}/{{ values.project.environment }}"After resolution, this becomes:
project:
name: "my-microservice"
version: "1.2.0"
environment: "production"
docker:
registry: "ghcr.io/mycompany"
image: "ghcr.io/mycompany/my-microservice:1.2.0"
database:
name: "my_microservice_production"
host: "my-microservice-production.cluster.amazonaws.com"
api:
base_url: "https://my-microservice.production.mycompany.com"
health_check: "https://my-microservice.production.mycompany.com/health"
monitoring:
namespace: "my-microservice/production"- π Reference Other Values: Use
{{ values.path.to.value }}syntax to reference any value in your configuration - π Chained References: References can reference other references for complex compositions
- π οΈ Jinja2 Filters: Apply filters like
{{ values.name | lower | replace('-', '_') }} - β‘ Smart Resolution: Automatic dependency resolution regardless of definition order
- π‘οΈ Circular Detection: Clear error messages for circular dependencies
- π Type Preservation: Maintains original data types (strings, numbers, booleans, lists)
Microservices Configuration:
environment: "prod"
region: "us-east-1"
project:
name: "ecommerce"
version: "2.1.0"
services:
api:
name: "{{ values.project.name }}-api"
image: "{{ values.docker.registry }}/{{ values.services.api.name }}:{{ values.project.version }}"
url: "https://{{ values.services.api.name }}.{{ values.environment }}.example.com"
frontend:
name: "{{ values.project.name }}-web"
image: "{{ values.docker.registry }}/{{ values.services.frontend.name }}:{{ values.project.version }}"
docker:
registry: "123456789012.dkr.ecr.{{ values.region }}.amazonaws.com"
database:
host: "{{ values.project.name }}-{{ values.environment }}.cluster-xyz.{{ values.region }}.rds.amazonaws.com"Kubernetes/Helm Values Pattern:
global:
namespace: "my-app-prod"
imageTag: "v1.2.3"
app:
name: "my-application"
fullName: "{{ values.global.namespace }}-{{ values.app.name }}"
secrets:
name: "{{ values.app.fullName }}-secrets"
dockerRegistry: "{{ values.app.fullName }}-registry-secret"Control reference resolution with CLI flags:
# Enable verbose mode to see resolution details
customizer process --project ./template --config ./config.yml --verbose --dry-run
# Disable reference resolution for compatibility
customizer process --project ./template --config ./config.yml --no-resolve-refs --dry-runTemplate Customizer provides clear error messages for configuration issues:
# Circular dependency detection
β Circular dependency detected in configuration file 'config.yml':
Circular dependency detected: a β b β c β a
Please check your configuration for references that form a loop.
# Missing reference detection
β Reference resolution failed in configuration file 'config.yml':
Reference 'values.missing.value' not found
Please ensure all referenced values exist in your configuration.For files that don't support comments (like JSON) or when you prefer external configuration, Template Customizer supports external replacement definitions in your config file.
JSON files don't support comments, so use JSONPath expressions in your config:
# config.yml
project:
name: "my-app"
version: "2.0.0"
author: "Jane Developer"
replacements:
json:
"package.json":
"$.name": "{{ values.project.name }}"
"$.version": "{{ values.project.version }}"
"$.author": "{{ values.project.author }}"
"$.scripts.start": "node {{ values.project.name }}.js"
"$.dependencies.react": "^18.0.0"
"$.config.port": "{{ values.server.port }}"
"$.config.debug": true # Booleans are preservedReplace content in Markdown files using patterns:
replacements:
markdown:
"README.md":
"pattern: # Old Title": "# {{ values.project.name | title }}"
"pattern: Version: .*": "Version: {{ values.project.version }}"
"pattern: Copyright \\(c\\) \\d+": "Copyright (c) 2024"
"literal: [PLACEHOLDER]": "{{ values.project.description }}" # Literal string (no regex)- JSONPath Support: Use standard JSONPath expressions to target any value in JSON files
- Pattern Matching: Use regex patterns or literal strings for Markdown/text files
- Type Preservation: JSON types (strings, numbers, booleans) are automatically preserved
- Template Rendering: Full Jinja2 template support in replacement values
- No Comment Pollution: Keep your JSON and other files clean without comment markers
Before (package.json):
{
"name": "template-project",
"version": "0.0.0",
"author": "Template Author"
}After (with external replacements):
{
"name": "my-app",
"version": "2.0.0",
"author": "Jane Developer"
}Template Customizer gracefully handles missing configuration values:
β Warning: docker-compose.yml has 3 missing values:
Line 5: web_image - Missing value 'values.docker.web_image': 'dict object' has no attribute 'docker'
Line 8: api_port - Missing value 'values.docker.api_port': 'dict object' has no attribute 'docker'
Line 12: debug_mode - Missing value 'values.environment.debug': 'dict object' has no attribute 'environment'
β Found 7 changes in 4 files
βΉ Processed 2 files with warningsFiles with missing values are still copied to the output directory, allowing you to incrementally build your configuration.
- Usage Guide - Detailed examples and advanced usage
- Development Guide - Contributing and development setup
- API Documentation - Complete API reference
- Issues: Report bugs and request features on GitHub Issues
- Discussions: For questions and community support
- Examples: Check the
examples/directory for template samples
We welcome contributions! Please see our Development Guide for setup instructions and guidelines.
MIT License - see LICENSE file for details.
π‘ Key Innovation: Template Customizer uses comment-based markers that preserve your template's functionality. Unlike traditional templating tools that break compilation with placeholder variables like ${APP_NAME} or {{app_name}}, your templates remain fully functional during development. This means:
- β Your IDE won't show syntax errors
- β Your code compiles and runs during template development
- β Your tests pass before and after customization
- β Your templates are maintainable and debuggable
Start using Template Customizer today and make your templates work for you, not against you!