Releases: cookiecutter/cookiecutter
Cookiecutter 2.7.1: The One Where It Knows Its Own Name
You know that thing where you release an album, it's on the shelves, people are buying it, and then someone points out the spine says it's your previous album? That's what happened with Cookiecutter 2.7.0. We put out the long-awaited release with 27 improvements and 17 contributors, and cookiecutter -V proudly announced: 2.6.0.
$ cookiecutter -V
Cookiecutter 2.6.0
$ # narrator voice: it was not 2.6.0
Go on, run this and see for yourself that the 2.7.1 release knows its own version number now:
uv tool upgrade cookiecutterWhat's fixed
cookiecutter -V now reports the real version. Rather than patch VERSION.txt, this release removes it entirely. The version is now read from package metadata at runtime, so pyproject.toml is the single source of truth and there's nothing left to drift. Thanks @bollwyvl for the bug report PR and for suggesting the importlib.metadata approach, and thanks @tranzystorekk for filing #2195!
What's better
CI runs each Python version as its own job. Tests for 3.10 through 3.14 used to run sequentially inside a single job per OS, which pushed Windows past 30 minutes. Each version now runs in parallel with a 15-minute timeout. Windows tests focus on the boundary versions (3.10 and 3.14) since intermediate versions add little signal beyond Ubuntu and macOS.
Contributors
@audreyfeldroy (Audrey M. Roy Greenfeld) and @pydanny (Daniel Roy Greenfeld) built this release, with help from Claude roleplaying as David Bowie.
Thanks to @bollwyvl (Nicholas Bollweg) for the version fix PR and the importlib.metadata suggestion, and @tranzystorekk for reporting the version mismatch.
2.7.0
Cookiecutter 2.7.0 is tested on Python 3.10 through 3.14, ships with a security policy documenting the trust model for template hook scripts, and publishes to PyPI with cryptographic provenance so you can verify every release. Seventeen contributors from the community helped build it.
uv tool upgrade cookiecutterWhat's new
A security policy that explains what you're trusting. Cookiecutter templates can run arbitrary code through hook scripts, and that's by design. The new SECURITY.md lays out the trust model: what Cookiecutter sandboxes (nothing), what's in scope for vulnerability reports, and how to report them privately through GitHub. If you maintain templates or run unfamiliar ones, this is worth reading.
Python 3.10 through 3.14. Full test coverage across five Python versions. If you're on 3.7, 3.8, or 3.9, this is the release where you'll want to upgrade.
Pretty-printed JSON in templates. The jsonify Jinja2 extension takes an indent argument, so you can generate formatted JSON in your templates instead of single-line blobs. Thanks @pabloxio! (#2050)
Boolean variables from the command line. Pass use_docker=y via --no-input and it arrives as a proper boolean in your template context. Thanks @tylermilner! (#2029)
Structured bug reports. The GitHub issue form collects environment details upfront, so maintainers can reproduce your issue faster.
Tutorial videos and slides. Conference talk recordings and slide decks linked from the docs. Thanks @datasharp! (#2137)
What's better
Verified PyPI releases. Every release is published via OpenID Connect (no stored API tokens) with SLSA provenance attestations. You can cryptographically verify that the package you installed was built from this repository's CI.
Same results on every OS. Template generation produces deterministic directory ordering regardless of platform. No more platform-specific file conflict surprises. Thanks @RaulWCosta! (#2099)
Zip-based templates release file handles immediately. No more locked-file issues on Windows when using cached zip templates. Thanks @mohiuddin-khan-shiam! (#2147)
Type-checked top to bottom. mypy coverage spans the entire codebase, with type hints added module by module. Thanks @danieleades for the massive effort! (#2015, #2041, #2042, #2051, #2053–#2056, #2059, #2060)
Ruff everywhere. Linting and formatting moved from flake8/isort/black to Ruff, with expanded rule groups covering pyflakes, pygrep, perf, and string formatting. Thanks @danieleades! (#2012, #2014, #2016, #2019, #2020, #2061)
Modern packaging. Config lives in pyproject.toml, with separated dependency groups for lint and test. Thanks @jensens! (#2040)
Clearer installation docs. The README includes pipx as an alternative, and the programmatic usage example is corrected. Thanks @swikrityy-yy and @christine-ho-dev! (#2165, #2122)
What's fixed
Empty lists in cookiecutter.json raise a clear error. A template with [] as a default value gets a helpful ValueError instead of a confusing IndexError. Thanks @meganlkm! (#2171)
Directory names that render to empty strings. Handled gracefully instead of failing silently. Thanks @DanielZhangD! (#1991)
Development dependency updates (no user impact)
The safety vulnerability scanner in the lint dependency group pulls in its own tree of transitive dependencies. These packages are never installed by pip install cookiecutter or uv tool install cookiecutter. We updated the lockfile to resolve 8 CVEs across nltk, urllib3, cryptography, authlib, filelock, and marshmallow (CVE-2025-14009, CVE-2026-21441, CVE-2026-26007, and 5 others).
No Cookiecutter user was exposed to these vulnerabilities.
Contributors
@audreyfeldroy (Audrey M. Roy Greenfeld) designed and built this release: the security policy, Python 3.14 support, dependency hardening, bug report form, and packaging modernization.
@pydanny (Daniel Roy Greenfeld) modernized the CI/CD workflow, migrated docs to justfile, and updated Python version support.
Thanks to:
- @danieleades for the massive type checking and linting overhaul across the entire codebase
- @tylermilner (Tyler Milner) for boolean CLI variable conversion
- @pabloxio (Pablo Jaramillo) for the
jsonifyindent parameter - @RaulWCosta (Raul Wagner Costa) for deterministic directory ordering
- @meganlkm (Megan Wood) for the empty list error handling
- @mohiuddin-khan-shiam for proper ZipFile handle cleanup
- @DanielZhangD (Daniel Zhang) for the directory name rendering fix
- @jensens (Jens W. Klein) for migrating configuration to pyproject.toml
- @kurtmckee (Kurt McKee) for upgrading to safety v3
- @luzfcb (Fábio C. Barrionuevo da Luz) for pytest config modernization
- @datasharp (Kayla Sharp) for tutorial video and slide links
- @christine-ho-dev (Christine Ho) for fixing the README programmatic example
- @swikrityy-yy (Swikriti Adhikari) for clarifying installation instructions
- @krishivs789 (Krishiv S) for stabilizing the README logo URL
- @Fred-si (Frédéric) for updating CONTRIBUTING.md
- @jkomalley (Kyle) for fixing outdated README shield URLs
- @dominiqueplante (Dominique Plante) for README updates
2.6.0
Changes
Minor Changes
CI/CD and QA changes
- Add isort as a pre-commit hook (#1988) @kurtmckee
- Bump actions/setup-python from 4 to 5 (#2000) @dependabot
- Bump actions/upload-artifact from 3 to 4 (#1999) @dependabot
- Quick resolution of #2003 (#2004) @jensens
- Support Python 3.12 (#1989) @ericof
- [pre-commit.ci] pre-commit autoupdate (#1996) @pre-commit-ci
Documentation updates
Bugfixes
- Fix regression #2009: Adding value to nested dicts broken (#2010) @jensens
- Fixed errors caused by invalid config files. (#1995) @alanverresen
- Quick resolution of #2003 (#2004) @jensens
This release is made by wonderful contributors:
@alanverresen, @dependabot, @dependabot[bot], @ericof, @jensens, @kurtmckee, @pre-commit-ci, @pre-commit-ci[bot] and @sacha-c
2.5.0
Changes
Minor Changes
- Default values can be passed as a dict (#1924) @matveyvarg
- Implement new style for nested templates config (#1981) @ericof
CI/CD and QA changes
- Bump actions/checkout from 3 to 4 (#1953) @dependabot
- [pre-commit.ci] pre-commit autoupdate (#1977) @pre-commit-ci
- [pre-commit.ci] pre-commit autoupdate (#1957) @pre-commit-ci
Documentation updates
- Add argument run to pipx command in README.md (#1964) @staeff
- Fix tutorial2 generated HTML (#1971) @aantoin
- Implement new style for nested templates config (#1981) @ericof
- Update README.md (#1967) @HarshRanaOC
- Update README.md to fix broken link (#1952) @david-abn
- Update README.md to include installation instructions (#1949) @david-abn
- Update cookiecutter-plone-starter link in readme (#1965) @zahidkizmaz
Bugfixes
- Fix FileExistsError when using a relative template path (#1968) @pkrueger-cariad
- Fix recursive context overwrites (#1961) @padraic-padraic
This release is made by wonderful contributors:
@HarshRanaOC, @aantoin, @david-abn, @dependabot, @dependabot[bot], @ericof, @matveyvarg, @padraic-padraic, @pkrueger-cariad, @pre-commit-ci, @pre-commit-ci[bot], @staeff and @zahidkizmaz
2.4.0
Changes
Minor Changes
- Gracefully handle files with mixed lined endings (#1942) @EricHripko
- Implement a pre_prompt hook that will run before prompts (#1950) @ericof
Documentation updates
- Implement a pre_prompt hook that will run before prompts (#1950) @ericof
- update main docstrings to include overwrite_if_exists and skip_if_file_exists (#1947) @david-abn
This release is made by wonderful contributors:
@EricHripko, @david-abn and @ericof
2.3.1
Changes
Minor Changes
- add checkout details to the context (fixes #1759) (#1923) @JonZeolla
CI/CD and QA changes
- Update the black pre-commit hook URL and version (#1934) @kurtmckee
- Use UTF-8 for file reading/writing (#1937) @rmartin16
Documentation updates
- Add missing "parent dir" symbol in tutorial 2 (#1932) @tvoirand
- Remove colons from exemplary prompt messages (#1912) @paduszyk
- docs: add install instruction for Void Linux (#1917) @tranzystorek-io
Bugfixes
- Fix nested templates in Git repository (#1922) @BTatlock
- Fix prompt counter. (#1940) @ericof
- Fix variables with null default not being required (#1919) (#1920) @limtis0
This release is made by wonderful contributors:
@BTatlock, @JonZeolla, @ericof, @kurtmckee, @limtis0, @paduszyk, @rmartin16, @tranzystorek-io and @tvoirand
2.3.0
Changes
Minor Changes
CI/CD and QA changes
- Bump paambaati/codeclimate-action from 4.0.0 to 5.0.0 (#1908) @dependabot
- [pre-commit.ci] pre-commit autoupdate (#1907) @pre-commit-ci
Bugfixes
This release is made by wonderful contributors:
@Meepit, @dependabot, @dependabot[bot], @ericof, @pre-commit-ci, @pre-commit-ci[bot] and @vemonet
2.2.3
Changes
Minor Changes
- Add support for adding human-readable labels for choices when defining multiple choices questions (#1898) @vemonet
- Prompt with replay file (#1758) @w1ndblow
CI/CD and QA changes
- Set cookiecutter/VERSION.txt as source of truth for version number (#1896) @ericof
- [pre-commit.ci] pre-commit autoupdate (#1897) @pre-commit-ci
Bugfixes
- Fix issue where the prompts dict was not passed for yes_no questions (#1895) @vemonet
- Set cookiecutter/VERSION.txt as source of truth for version number (#1896) @ericof
This release is made by wonderful contributors:
@ericof, @pre-commit-ci, @pre-commit-ci[bot], @vemonet and @w1ndblow
2.2.2
Changes
CI/CD and QA changes
- Improve gitignore (#1889) @audreyfeldroy
Documentation updates
This release is made by wonderful contributors:
2.2.0
Changes
- Added timeout on request.get() for ensuring that if a recipient serve… (#1772) @openrefactory
- Fixing Carriage Return Line Feed (CRLF) order in docs #1792 (#1793) @Lahiry
- Reduce I/O (#1877) @kurtmckee
- Remove a pre-commit hook special case (#1875) @kurtmckee
- Remove universal bdist_wheel option; use "python -m build" (#1739) @mwtoews
- Remove unused import from post-generate hook script example (#1795) @KAZYPinkSaurus
- Standardize newlines for all platforms (#1870) @kurtmckee
- feat: Add resolved template repository path as _repo_dir to the context (#1771) @tmeckel
Minor Changes
- Added support for providing human-readable prompts to the different variables (#1881) @vemonet
- Added: Boolean variable support in JSON (#1626) @liortct
- Added: CLI option to keep project files on failure. (#1669) @MaciejPatro
- Added: Support partially overwrite keys in nested dict (#1692) @cksac
- Added: Templates inheritance (#1485) @simobasso
- Code quality: Tests upgrade: Use pathlib for files read/write (#1718) @insspb
- Inline jinja2-time extension code (#1779) @tranzystorek-io
- Support Python 3.11 (#1850) @kurtmckee
- Support nested config files (#1770) @dariocurr
- preserves original options in
_cookiecutter(#1874) @kjaymiller
CI/CD and QA changes
- Add a Dependabot config to autoupdate GitHub workflow actions (#1851) @kurtmckee
- Added: Readthedocs build config (#1707) @insspb
- Bump actions/setup-python from 3 to 4 (#1854) @dependabot
- Bump paambaati/codeclimate-action from 3.0.0 to 4.0.0 (#1853) @dependabot
- CI/CD: Tox -> Nox: Added nox configuration (#1706) @insspb
- CI/CD: Tox -> Nox: Github actions definition minimized + Sync nox and github actions (#1714) @insspb
- CI/CD: Tox -> Nox: Makefile update: Removed watchmedo and sed dependency, tox replaced with nox (#1713) @insspb
- CI/CD: Updated .pre-commit-config.yaml to use latest hooks versions (#1712) @insspb
- Code quality: Core files: Added exception reason reraise when exception class changed (PEP 3134) (#1719) @insspb
- Code quality: Tests upgrade: Use pathlib for files read/write (#1718) @insspb
- Code quality: core files: Format replaced with f-strings (#1716) @insspb
- Code quality: find.py refactored and type annotated (#1721) @insspb
- Code quality: tests files: Simplify statements fixes (#1717) @insspb
- Code quality: utils.make_sure_path_exists refactored and type annotated (#1722) @insspb
- Fixed: recommonmark replaced with myst, as recommonmark is deprecated (#1709) @insspb
- Pretty-format JSON files (#1864) @kurtmckee
- Rename
mastertomainso CI runs correctly on merge (#1852) @kurtmckee - Standardize EOF newlines (#1876) @kurtmckee
- Update
.gitignoreand cite where it was copied from (#1879) @kurtmckee - Update base docs, remove tox (#1858) @ericof
- Update pre-commit hook versions (#1849) @kurtmckee
- Updated: Release drafter configuration (#1704) @insspb
- Use tox (#1866) @kurtmckee
- Verify an expected warning is raised (#1869) @kurtmckee
- fixed failing lint ci action by updating repo of flake8 (#1838) @Tamronimus
Documentation updates
- Add jinja env docs (#1872) @pamelafox
- Documentation extension: Create a Cookiecutter From Scratch tutorial (#1592) @miro-jelaska
- Easy PR! Fix typos and add minor doc updates (#1741) @Alex0Blackwell
- Expand cli documentation relating to the no-input flag (#1543) (#1587) @jeremyswerdlow
- Fix @audreyr to @audreyfeldroy github account rename (#1604) @ri0t
- Fixed broken links to jinja docs (#1691) @insspb
- Fixed minor typos in docs (#1753) @segunb
- Fixed: Python code block in the replay documentation (#1715) @juhannc
- Fixed: recommonmark replaced with myst, as recommonmark is deprecated (#1709) @insspb
- Improve Docs Readability (#1690) @ryanrussell
- Update base docs, remove tox (#1858) @ericof
- Updated: Boolean Variables documentation and docstrings (#1705) @italomaia
- docs: fix simple typo, shat -> that (#1749) @timgates42
- fixing badge display problem (#1798) @Paulokim1
Bugfixes
- Fixed the override not working with copy only dir #1650 (#1651) @zhongdai
- Fixed: Removed mention of packages versions, to exclude dependabot warnings alerts (#1711) @insspb
- cleanup files if panics during hooks - bugfix (#1760) @liortct
This release is made by wonderful contributors:
@Alex0Blackwell, @KAZYPinkSaurus, @Lahiry, @MaciejPatro, @Paulokim1, @Tamronimus, @cksac, @cookies-xor-cream, @dariocurr, @dependabot, @dependabot[bot], @ericof, @insspb, @italomaia, @jeremyswerdlow, @juhannc, @kjaymiller, @kurtmckee, @liortct, @miro-jelaska, @mwtoews, @openrefactory, @pamelafox, @ri0t, @ryanrussell, @segunb, @simobasso, @timgates42, @tmeckel, @tranzystorek-io, @vemonet and @zhongdai