Cookiecutter uses Jinja2 as its template engine. This guide covers the advanced features you can use in file names, content, and cookiecutter.json.
All cookiecutter.json variables are available as {{ cookiecutter.xxx }}:
{{ cookiecutter.project_name }}
{{ cookiecutter.author_name }}
{{ cookiecutter.version }}Jinja2 supports chained filters with |:
{{ cookiecutter.project_name|lower }} # "my project"
{{ cookiecutter.project_name|upper }} # "MY PROJECT"
{{ cookiecutter.project_name|title }} # "My Project"
{{ cookiecutter.project_name|trim }} # no leading/trailing spaces
{{ cookiecutter.project_name|replace(' ', '_') }} # "my_project"
{{ cookiecutter.project_name|replace(' ', '-') }} # "my-project"
{{ cookiecutter.project_name|length }} # 11 (number of chars)
{{ cookiecutter.version|replace('.', '') }} # "010" for v0.1.0{{ cookiecutter.project_name|lower|replace(' ', '_')|replace('-', '_') }}With project_name = "My Awesome-Project":
my_awesome_project
Converts a value to JSON. Useful in hooks and for generating valid JSON:
{{ cookiecutter.use_docker|tojson }}With use_docker = "yes" → "yes" (with JSON quotes).
# setup.py
setup(
name="{{ cookiecutter.project_slug }}",
version="{{ cookiecutter.version }}",
{% if cookiecutter.license == "MIT" %}
license="MIT",
{% elif cookiecutter.license == "Apache-2.0" %}
license="Apache 2.0",
{% else %}
# license: {{ cookiecutter.license }}
{% endif %}
){{ "with Docker" if cookiecutter.use_docker == "yes" else "without Docker" }}{% if cookiecutter.database == "postgresql" %}
DATABASE_URL = "postgresql://localhost/{{ cookiecutter.project_slug }}"
{% elif cookiecutter.database == "sqlite" %}
DATABASE_URL = "sqlite:///{{ cookiecutter.project_slug }}.db"
{% endif %}# requirements.txt
{% for package in cookiecutter.packages.split(',') %}
{{ package.strip() }}
{% endfor %}With packages = "flask,requests,pytest":
flask
requests
pytest
{% for ext in cookiecutter.extensions.split(',') if ext.strip() %}
import {{ ext.strip() }}
{% endfor %}Jinja2 leaves blank lines when processing tags. Use hyphens to control whitespace:
{%- if cookiecutter.use_docker == "yes" -%}
FROM python:{{ cookiecutter.python_version }}
{%- endif -%}{%-removes whitespace before the tag.-%}removes whitespace after the tag.
# {{ cookiecutter.project_name }}
{% if cookiecutter.use_docker == "yes" -%}
## Docker
```bash
docker build -t {{ cookiecutter.project_slug }} .
docker run {{ cookiecutter.project_slug }}{% endif %} {%- if cookiecutter.use_ci == "yes" %}
Configured with {{ cookiecutter.ci_provider }}. {% endif -%}
---
## Macros
```jinja2
{% macro license_header(license_type, author) -%}
{%- if license_type == "MIT" %}
# MIT License
# Copyright (c) {{ author }}
{%- elif license_type == "Apache-2.0" %}
# Apache License 2.0
# Copyright (c) {{ author }}
{%- endif %}
{%- endmacro %}
{{ license_header(cookiecutter.license, cookiecutter.author_name) }}
Create custom filters in _extensions/:
my-template/
├── _extensions/
│ └── my_filters.py
├── cookiecutter.json
└── {{ cookiecutter.project_name }}/
# _extensions/my_filters.py
import re
def slugify(value):
value = value.lower().strip()
value = re.sub(r'[^\w\s-]', '', value)
value = re.sub(r'[\s_-]+', '-', value)
return re.sub(r'^-+|-+$', '', value)
def camel_case(value):
value = value.replace('_', ' ').replace('-', ' ')
return ''.join(word.capitalize() for word in value.split())
def snake_case(value):
value = value.replace('-', ' ').replace('.', ' ')
return '_'.join(word.lower() for word in value.split())Register in cookiecutter.json:
{
"_extensions": ["my_filters.slugify", "my_filters.camel_case", "my_filters.snake_case"],
"project_name": "My Project",
"project_slug": "{{ cookiecutter.project_name|slugify }}",
"class_name": "{{ cookiecutter.project_name|camel_case }}"
}With project_name = "My Awesome Project":
project_slug→my-awesome-projectclass_name→MyAwesomeProject
{
"project_name": "My Project",
"project_slug": "{{ cookiecutter.project_name|lower|replace(' ', '_') }}",
"pkg_name": "{{ cookiecutter.project_slug|replace('_', '') }}",
"repo_name": "{{ cookiecutter.project_name|lower|replace(' ', '-') }}",
"class_name": "{{ cookiecutter.project_name|replace(' ', '') }}"
}These variables are computed automatically and not shown in the prompt.
{
"project_name": "My Project",
"year": "{{ cookiecutter.year }}",
"copyright": "Copyright (c) {{ cookiecutter.year }} {{ cookiecutter.author_name }}"
}{# In an __init__.py file #}
"""
{{ cookiecutter.project_name }} package.
"""
__version__ = "{{ cookiecutter.version }}"
{% for module in cookiecutter.modules.split(',') %}
from . import {{ module.strip() }}
{% endfor %}# config.yaml
project:
name: {{ cookiecutter.project_name }}
version: {{ cookiecutter.version }}
{% if cookiecutter.environment == "production" %}
debug: false
{% else %}
debug: true
{% endif %}
database:
type: {{ cookiecutter.database }}
{% if cookiecutter.database == "postgresql" %}
host: {{ cookiecutter.db_host|default("localhost") }}
port: {{ cookiecutter.db_port|default(5432) }}
{% elif cookiecutter.database == "sqlite" %}
path: ./{{ cookiecutter.project_slug }}.db
{% endif %}{# LICENSE #}
{% if cookiecutter.license == "MIT" %}
MIT License
Copyright (c) {{ cookiecutter.year }} {{ cookiecutter.author_name }}
Permission is hereby granted, free of charge, to any person obtaining a copy
...
{% elif cookiecutter.license == "Apache-2.0" %}
Apache License, Version 2.0
...
{% elif cookiecutter.license == "proprietary" %}
Proprietary - {{ cookiecutter.author_name }}
All rights reserved.
{% endif %}If you need literal {{ }} in a file (that is not Jinja2), use:
{{ "{{ cookiecutter.project_name }}" }} # produces literal {{ cookiecutter.project_name }}Or use _copy_without_render to exclude the file from Jinja2 processing.