Tools & Integrations

July 6, 2026 · View on GitHub

Cookiecutter extensions

ToolDescriptionURL
cookiecutterOfficial CLIcookiecutter/cookiecutter
cookiecutter-pytestTemplate testing with pytestfrost/cookiecutter-pytest
cruftManage updates for projects created with cookiecuttercruft/cruft
cookiecutter-vscodeVS Code extensionVS Code Marketplace

Alternatives and Complements

ToolDescription
CopierModern alternative, supports updates
PyscaffoldPython scaffolding with more structure
Pyproject-fmtFormatter for pyproject.toml
Pre-commitGit hooks for code quality

CI/CD

GitHub Actions

# .github/workflows/test-template.yml
name: Test Template
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v4
        with:
          python-version: "3.11"
      - run: pip install cookiecutter pytest
      - run: cookiecutter --no-input . project_name=TestProject --output-dir /tmp/test
      - run: pytest tests/

Pre-commit hook

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/cookiecutter/cookiecutter
    rev: 2.5.0
    hooks:
      - id: cookiecutter

IDE Plugins

VS Code

  • Cookiecutter extension — generate projects from the command palette.
  • Search "cookiecutter" in the marketplace.

PyCharm / IntelliJ

  • File → New → Project → Cookiecutter (natively integrated).
  • Configure the template path or Git URL.

Maintenance with Cruft

cruft keeps projects up to date when the template changes:

# Create project from template
cruft create https://github.com/user/cookiecutter-template.git

# Check for updates
cruft check

# Apply updates
cruft update

Template Testing

Manual

cookiecutter --no-input ./my-template project_name=Test --output-dir /tmp/test
find /tmp/test -type f

Automated with pytest

import subprocess
from pathlib import Path


def test_template_generates(tmp_path):
    result = subprocess.run(
        ["cookiecutter", "--no-input", "./my-template",
         "project_name=Test", f"--output-dir={tmp_path}"],
        capture_output=True, text=True,
    )
    assert result.returncode == 0
    project = tmp_path / "test"
    assert project.exists()
    assert (project / "README.md").exists()