Aller au contenu
Outils medium

Cookiecutter : générer des projets standardisés en 10 secondes

10 min de lecture

Cookiecutter génère une structure de projet complète en une commande. Vous choisissez un template (local ou GitHub), répondez à quelques questions, et obtenez un projet prêt à coder. Ce guide couvre l’installation, l’utilisation des templates existants et la création de vos propres templates.

Démarrer un nouveau projet implique toujours les mêmes tâches :

  • Créer la structure de dossiers
  • Ajouter les fichiers de configuration (.gitignore, pyproject.toml, Dockerfile)
  • Copier du code boilerplate depuis un ancien projet
  • Renommer les variables, nettoyer les références au projet précédent

Ce processus prend 30 minutes à 2 heures selon la complexité. Pire, chaque développeur fait différemment, créant des incohérences dans l’équipe.

Cookiecutter automatise tout cela :

Sans CookiecutterAvec Cookiecutter
Copier-coller d’un ancien projetUne commande génère la structure
Rechercher/remplacer les nomsVariables pré-remplies automatiquement
Oublier des fichiers de configTemplate complet et cohérent
30 min à 2h par projet10 secondes

Version actuelle : 2.6.0 (février 2026)

Cookiecutter est écrit en Python. L’installation recommandée utilise pipx pour isoler les dépendances.

  1. Installer pipx (si pas déjà fait)

    Fenêtre de terminal
    # Ubuntu/Debian
    sudo apt install pipx
    pipx ensurepath
    # Ou avec pip
    pip install --user pipx
    pipx ensurepath
  2. Installer Cookiecutter

    Fenêtre de terminal
    pipx install cookiecutter

    Sortie attendue :

    done! ✨ 🌟 ✨
    installed package cookiecutter 2.6.0, installed using Python 3.12.3
    These apps are now globally available
    - cookiecutter
  3. Vérifier l’installation

    Fenêtre de terminal
    cookiecutter --version
    # Cookiecutter 2.6.0

La façon la plus simple d’utiliser Cookiecutter : pointer vers un template GitHub.

Fenêtre de terminal
cookiecutter https://github.com/audreyfeldroy/cookiecutter-pypackage

Cookiecutter clone le dépôt, lit le fichier cookiecutter.json, et vous pose les questions :

full_name [Audrey Roy Greenfeld]: Stéphane Robert
email [audreyr@example.com]: me@stephane-robert.info
project_name [Python Boilerplate]: Mon Super Projet
project_slug [mon_super_projet]:
...

Le projet est généré dans le dossier courant :

Fenêtre de terminal
ls mon_super_projet/
# CODE_OF_CONDUCT.md docs/ LICENSE pyproject.toml README.md src/ tests/

Pour les pipelines CI/CD ou les scripts, utilisez --no-input :

Fenêtre de terminal
cookiecutter https://github.com/audreyfeldroy/cookiecutter-pypackage --no-input

Cookiecutter utilise les valeurs par défaut du template.

Fenêtre de terminal
cookiecutter https://github.com/user/template \
project_name="Mon Projet" \
author_name="Stéphane"
Fenêtre de terminal
cookiecutter https://github.com/user/template --checkout v1.0.0

Cookiecutter met en cache les templates. Pour les lister :

Fenêtre de terminal
cookiecutter --list-installed
# 1 installed templates:
# * cookiecutter-pypackage

Pour réutiliser un template déjà cloné :

Fenêtre de terminal
cookiecutter cookiecutter-pypackage

Au cœur de chaque template, ce fichier JSON définit les variables et leurs valeurs par défaut.

{
"project_name": "Mon Projet",
"author_name": "Stéphane Robert",
"version": "0.1.0",
"description": "Un projet Python"
}

Chaque clé devient une variable utilisable dans les fichiers du template avec la syntaxe Jinja2 : {{ cookiecutter.project_name }}.

{
"license": ["MIT", "GPLv3", "Apache 2.0", "BSD-3-Clause"],
"use_docker": ["yes", "no"]
}

L’utilisateur sélectionne parmi les options. La première option est la valeur par défaut.

{
"project_name": "Mon Super Projet",
"project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_') }}"
}

project_slug est calculé automatiquement à partir de project_name.

  • Répertoiremon-template/
    • cookiecutter.json
    • Répertoire{{cookiecutter.project_name}}/
      • README.md
      • .gitignore

Le dossier {{cookiecutter.project_name}} sera renommé avec la valeur saisie par l’utilisateur.

Créons un template pour un projet avec Docker et CI/CD :

  1. Créer la structure

    Fenêtre de terminal
    mkdir -p mon-template/\{\{cookiecutter.project_name\}\}/.github/workflows
    cd mon-template
  2. Créer cookiecutter.json

    Fenêtre de terminal
    cat > cookiecutter.json << 'EOF'
    {
    "project_name": "my-app",
    "author_name": "Stéphane Robert",
    "description": "Application DevOps",
    "python_version": ["3.12", "3.11", "3.10"],
    "include_docker": ["yes", "no"],
    "include_ci": ["yes", "no"]
    }
    EOF
  3. Créer les fichiers du template

    {{cookiecutter.project_name}}/README.md :

    # {{ cookiecutter.project_name }}
    {{ cookiecutter.description }}
    ## Auteur
    {{ cookiecutter.author_name }}
    ## Installation
    ```bash
    pip install -e .
    \```

    {{cookiecutter.project_name}}/.gitignore :

    __pycache__/
    *.pyc
    .env
    .venv/
    dist/
    *.egg-info/
  4. Tester le template

    Fenêtre de terminal
    cd ..
    cookiecutter mon-template/

Utilisez Jinja2 dans les noms de fichiers pour créer des fichiers conditionnels :

  • Répertoiremon-template/
    • cookiecutter.json
    • Répertoire{{cookiecutter.project_name}}/
      • README.md
      • {{“Dockerfile” if cookiecutter.include_docker == “yes” else ""}}
      • Répertoire{{“.github” if cookiecutter.include_ci == “yes” else ""}}/
        • Répertoireworkflows/
          • ci.yml

Le Dockerfile n’est créé que si l’utilisateur répond “yes” à include_docker.

Dans un fichier, utilisez les conditions Jinja2 :

# {{ cookiecutter.project_name }}
{{ cookiecutter.description }}
{% if cookiecutter.include_docker == "yes" %}
## Docker
Build l'image :
\```bash
docker build -t {{ cookiecutter.project_name }} .
\```
{% endif %}
{% if cookiecutter.include_ci == "yes" %}
## CI/CD
Ce projet utilise GitHub Actions. Voir `.github/workflows/ci.yml`.
{% endif %}

Les hooks sont des scripts Python exécutés à différents moments de la génération.

HookMoment d’exécutionUsage typique
pre_prompt.pyAvant les questionsVérifier des prérequis
pre_gen_project.pyAvant générationValider les réponses
post_gen_project.pyAprès générationInitialiser Git, installer deps

Les hooks se placent dans le dossier hooks/ à la racine du template :

  • Répertoiremon-template/
    • cookiecutter.json
    • Répertoirehooks/
      • pre_gen_project.py
      • post_gen_project.py
    • Répertoire{{cookiecutter.project_name}}/

hooks/post_gen_project.py :

import subprocess
import os
def main():
project_path = os.getcwd()
# Initialiser Git
subprocess.run(["git", "init"], cwd=project_path, check=True)
subprocess.run(["git", "add", "."], cwd=project_path, check=True)
subprocess.run(
["git", "commit", "-m", "Initial commit from Cookiecutter"],
cwd=project_path,
check=True
)
print("✓ Dépôt Git initialisé avec le premier commit")
if __name__ == "__main__":
main()

hooks/pre_gen_project.py :

import re
import sys
def main():
project_name = "{{ cookiecutter.project_name }}"
if not re.match(r"^[a-zA-Z][a-zA-Z0-9_-]*$", project_name):
print("ERREUR: Le nom du projet doit commencer par une lettre")
print(" et ne contenir que lettres, chiffres, tirets ou underscores.")
sys.exit(1)
if __name__ == "__main__":
main()

Par défaut, Cookiecutter demande confirmation avant d’exécuter les hooks. Contrôlez ce comportement :

Fenêtre de terminal
# Toujours exécuter
cookiecutter template --accept-hooks yes
# Demander (défaut)
cookiecutter template --accept-hooks ask
# Jamais exécuter
cookiecutter template --accept-hooks no
OptionDescription
-V, --versionAffiche la version
--no-inputUtilise les valeurs par défaut
-c, --checkoutClone une branche/tag spécifique
-o, --output-dirDossier de destination
-f, --overwrite-if-existsÉcrase si le projet existe
-s, --skip-if-file-existsIgnore les fichiers existants
-l, --list-installedListe les templates en cache
--replayRéutilise les réponses précédentes
--accept-hooks`yes
TemplateDescriptionLien
cookiecutter-djangoDjango production-ready avec DockerGitHub
cookiecutter-pypackagePackage Python avec tests et CIGitHub
cookiecutter-ansible-roleRôle Ansible avec moléculeGitHub
cookiecutter-flaskFlask avec API REST et DockerGitHub

Pour définir des valeurs par défaut globales, créez ~/.cookiecutterrc :

default_context:
full_name: "Stéphane Robert"
email: "me@stephane-robert.info"
github_username: "stephrobert"
abbreviations:
gh: https://github.com/\{0\}.git
bb: https://bitbucket.org/\{0\}

Maintenant, utilisez les abréviations :

Fenêtre de terminal
cookiecutter gh:audreyfeldroy/cookiecutter-pypackage
  1. Cookiecutter = générateur de projets — Une commande génère une structure complète
  2. Templates GitHub : cookiecutter https://github.com/user/template
  3. cookiecutter.json définit les variables et valeurs par défaut
  4. Jinja2 pour le contenu dynamique : {{ cookiecutter.variable }}
  5. Fichiers conditionnels : nommez {{"Dockerfile" if var == "yes" else ""}}
  6. Hooks : scripts Python exécutés avant/après génération
  7. —no-input pour les pipelines CI/CD
  8. ~/.cookiecutterrc pour vos valeurs par défaut globales

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.