Python Copier Project Scaffolding — Core Concepts

Why Copier Exists

Cookiecutter proved that project scaffolding saves time. But it has a gap: once a project is generated, the connection to the template is severed. Copier closes that gap by tracking the template version and user answers inside the generated project, making future updates possible.

Install Copier with pip or pipx:

pipx install copier

Creating a Project

copier copy gh:your-org/python-template my-new-project

Copier asks the questions defined in the template, generates the project, and writes a .copier-answers.yml file inside it. This file records every answer and the exact template commit, creating a link back to the source.

Template Structure

A Copier template is a Git repository with a copier.yml (or copier.yaml) file at the root:

# copier.yml
project_name:
  type: str
  help: "Human-readable project name"

project_slug:
  type: str
  default: "{{ project_name | lower | replace(' ', '-') }}"

use_docker:
  type: bool
  default: true

python_version:
  type: str
  choices:
    - "3.11"
    - "3.12"
    - "3.13"
  default: "3.12"

_subdirectory: "project"

The _subdirectory key tells Copier that the actual template files live in a subfolder, keeping template config separate from template content.

The Update Workflow

This is Copier’s killer feature. When the template evolves:

cd my-new-project
copier update

Copier compares three states:

  1. Old template — the version recorded in .copier-answers.yml
  2. New template — the latest (or specified) version
  3. Your project — including your custom changes

It performs a three-way merge, applying template changes without overwriting your modifications. Conflicts are handled like Git merge conflicts — you resolve them manually.

Conditional Files with Jinja Suffixes

Instead of relying on hooks to delete unwanted files, Copier supports Jinja-powered file names natively:

{{ "Dockerfile" if use_docker }}
{{ ".github" if use_github_actions }}/workflows/ci.yml

When use_docker is false, the Dockerfile simply isn’t created. No cleanup scripts needed.

Migration Tasks

When a template upgrade involves breaking changes — like renaming a folder or changing a config format — Copier supports migration tasks:

# copier.yml
_tasks:
  - command: "python scripts/migrate.py"
    when: "{{ _copier_conf.old_version < '2.0' }}"

These run automatically during copier update, handling structural changes that a simple file diff cannot.

Common Misconception

“Copier is just Cookiecutter with updates.” While the update feature is the headline, Copier also has cleaner multi-choice handling, native type validation (bool, int, float, not just strings), and built-in support for template versioning through Git tags. The question schema alone makes templates more robust.

One thing to remember: Copier keeps a living connection between your project and its template — updates flow forward instead of forcing you to start over.

pythonproject-scaffoldingdeveloper-tools

See Also

  • Python Black Formatter Understand Black Formatter through a practical analogy so your Python decisions become faster and clearer.
  • Python Bumpversion Release Change your software's version number in every file at once with a single command — no more find-and-replace mistakes.
  • Python Changelog Automation Let your git commits write the changelog so you never forget what changed in a release.
  • Python Ci Cd Python Understand CI CD Python through a practical analogy so your Python decisions become faster and clearer.
  • Python Cicd Pipelines Use Python CI/CD pipelines to remove setup chaos so Python projects stay predictable for every teammate.