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 tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn