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, cohérent d'un développeur à l'autre.
Ce guide s'adresse aux développeurs et équipes DevOps qui répètent le même démarrage de projet. Vous allez installer Cookiecutter, utiliser des templates existants, créer le vôtre (avec cookiecutter.json et Jinja2), et automatiser des tâches avec des hooks.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Installer Cookiecutter proprement avec pipx.
- Générer un projet depuis un template GitHub ou local.
- Écrire votre propre template avec
cookiecutter.jsonet Jinja2. - Conditionner fichiers et contenus selon les réponses.
- Automatiser avec des hooks (init Git, validation).
Le problème que Cookiecutter résout
Section intitulée « Le problème que Cookiecutter résout »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 Cookiecutter | Avec Cookiecutter |
|---|---|
| Copier-coller d'un ancien projet | Une commande génère la structure |
| Rechercher/remplacer les noms | Variables pré-remplies automatiquement |
| Oublier des fichiers de config | Template complet et cohérent |
| 30 min à 2h par projet | 10 secondes |
Installation
Section intitulée « Installation »Version actuelle : 2.7.1 (mars 2026). Les versions 2.7.x corrigent des vulnérabilités des branches antérieures : gardez Cookiecutter à jour, surtout si vous exécutez des templates tiers.
Cookiecutter est écrit en Python. L'installation recommandée utilise pipx pour isoler les dépendances.
-
Installer pipx (si pas déjà fait)
Fenêtre de terminal # Ubuntu/Debiansudo apt install pipxpipx ensurepath# Ou avec pippip install --user pipxpipx ensurepath -
Installer Cookiecutter
Fenêtre de terminal pipx install cookiecutterSortie attendue :
done! ✨ 🌟 ✨installed package cookiecutter 2.7.1, installed using Python 3.12.3These apps are now globally available- cookiecutter -
Vérifier l'installation
Fenêtre de terminal cookiecutter --version# Cookiecutter 2.7.1
Utiliser un template existant
Section intitulée « Utiliser un template existant »Depuis GitHub
Section intitulée « Depuis GitHub »La façon la plus simple d'utiliser Cookiecutter : pointer vers un template GitHub.
cookiecutter https://github.com/audreyfeldroy/cookiecutter-pypackageCookiecutter clone le dépôt, lit le fichier cookiecutter.json, et vous pose les questions :
full_name [Audrey Roy Greenfeld]: Stéphane Robertemail [audreyr@example.com]: me@stephane-robert.infoproject_name [Python Boilerplate]: Mon Super Projetproject_slug [mon_super_projet]:...Le projet est généré dans le dossier courant :
ls mon_super_projet/# CODE_OF_CONDUCT.md docs/ LICENSE pyproject.toml README.md src/ tests/Mode non-interactif
Section intitulée « Mode non-interactif »Pour les pipelines CI/CD ou les scripts, utilisez --no-input :
cookiecutter https://github.com/audreyfeldroy/cookiecutter-pypackage --no-inputCookiecutter utilise les valeurs par défaut du template.
Passer des valeurs en ligne de commande
Section intitulée « Passer des valeurs en ligne de commande »Les paires clé=valeur placées après l'URL du template surchargent les valeurs par défaut du cookiecutter.json. Elles se combinent avec --no-input : les clés fournies prennent votre valeur, les autres gardent celle du template, et aucune question n'est posée. C'est la forme à privilégier en CI/CD, car elle rend la commande reproductible et lisible dans les journaux. Un nom de clé absent du cookiecutter.json est ignoré silencieusement, sans avertissement : vérifiez l'orthographe des variables avant de vous étonner du résultat.
cookiecutter https://github.com/user/template \ project_name="Mon Projet" \ author_name="Stéphane"Utiliser une version spécifique
Section intitulée « Utiliser une version spécifique »--checkout s'applique après le git clone du template et accepte une branche, un tag ou un commit. C'est la seule façon de garantir qu'une génération donne le même résultat dans six mois : sans cette option, Cookiecutter suit la branche par défaut du dépôt, qui évolue sans prévenir. Épinglez un tag pour la lisibilité, un commit quand vous voulez une garantie absolue, un tag pouvant être redéplacé par le mainteneur.
cookiecutter https://github.com/user/template --checkout v1.0.0Templates installés
Section intitulée « Templates installés »Cookiecutter met en cache les templates. Pour les lister :
cookiecutter --list-installed# 1 installed templates:# * cookiecutter-pypackagePour réutiliser un template déjà cloné :
cookiecutter cookiecutter-pypackageLe fichier cookiecutter.json
Section intitulée « Le fichier cookiecutter.json »Au cœur de chaque template, ce fichier JSON définit les variables et leurs valeurs par défaut.
Structure basique
Section intitulée « Structure basique »{ "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 }}.
Choix multiples
Section intitulée « Choix multiples »{ "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.
Variables dérivées
Section intitulée « Variables dérivées »{ "project_name": "Mon Super Projet", "project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_') }}"}project_slug est calculé automatiquement à partir de project_name.
Créer votre propre template
Section intitulée « Créer votre propre template »Structure minimale
Section intitulée « Structure minimale »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.
Exemple : template DevOps
Section intitulée « Exemple : template DevOps »Créons un template pour un projet avec Docker et CI/CD :
-
Créer la structure
Fenêtre de terminal mkdir -p mon-template/\{\{cookiecutter.project_name\}\}/.github/workflowscd mon-template -
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 -
Créer les fichiers du template
{{cookiecutter.project_name}}/README.md:# {{ cookiecutter.project_name }}{{ cookiecutter.description }}## Auteur{{ cookiecutter.author_name }}## Installation```bashpip install -e .```{{cookiecutter.project_name}}/.gitignore:__pycache__/*.pyc.env.venv/dist/*.egg-info/ -
Tester le template
Fenêtre de terminal cd ..cookiecutter mon-template/
Fichiers conditionnels
Section intitulée « Fichiers conditionnels »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.
Contenu conditionnel
Section intitulée « Contenu conditionnel »Dans un fichier, utilisez les conditions Jinja2 :
# {{ cookiecutter.project_name }}
{{ cookiecutter.description }}
{% if cookiecutter.include_docker == "yes" %}## Docker
Build l'image :
```bashdocker build -t {{ cookiecutter.project_name }} .```{% endif %}
{% if cookiecutter.include_ci == "yes" %}## CI/CD
Ce projet utilise GitHub Actions. Voir `.github/workflows/ci.yml`.{% endif %}Hooks : exécuter du code automatiquement
Section intitulée « Hooks : exécuter du code automatiquement »Les hooks sont des scripts Python exécutés à différents moments de la génération.
Types de hooks
Section intitulée « Types de hooks »| Hook | Moment d'exécution | Usage typique |
|---|---|---|
pre_prompt.py | Avant les questions | Vérifier des prérequis |
pre_gen_project.py | Avant génération | Valider les réponses |
post_gen_project.py | Après génération | Initialiser 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}}/
- ...
Exemple : initialiser Git après génération
Section intitulée « Exemple : initialiser Git après génération »hooks/post_gen_project.py :
import subprocessimport 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()Exemple : valider le nom du projet
Section intitulée « Exemple : valider le nom du projet »hooks/pre_gen_project.py :
import reimport 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()Gérer l'option accept-hooks
Section intitulée « Gérer l'option accept-hooks »Contrairement à une idée répandue, Cookiecutter exécute les hooks sans rien demander : la valeur par défaut de --accept-hooks est yes. Le mode ask, qui affiche la question Do you want to execute hooks?, doit être demandé explicitement. Un hook est un script Python arbitraire livré avec le template : lancer un template GitHub inconnu revient donc à exécuter le code de son auteur sur votre poste, avec vos droits.
# Toujours exécuter (comportement par défaut)cookiecutter template --accept-hooks yes
# Demander confirmation avant chaque exécutioncookiecutter template --accept-hooks ask
# Jamais exécutercookiecutter template --accept-hooks noOptions de ligne de commande
Section intitulée « Options de ligne de commande »Ce tableau retient les options les plus utiles au quotidien ; cookiecutter --help affiche la liste complète, notamment --directory pour un dépôt hébergeant plusieurs templates et --keep-project-on-failure pour inspecter un dossier partiellement généré après une erreur. Deux options sont mutuellement exclusives : --no-input et --replay refusent de cohabiter, la première ignore les réponses enregistrées tandis que la seconde les rejoue. Attention aussi à -f (--overwrite-if-exists), qui écrase les fichiers du dossier cible sans confirmation : -s (--skip-if-file-exists) est le comportement prudent quand vous régénérez par-dessus un projet existant.
| Option | Description |
|---|---|
-V, --version | Affiche la version |
--no-input | Utilise les valeurs par défaut |
-c, --checkout | Clone une branche/tag spécifique |
-o, --output-dir | Dossier de destination |
-f, --overwrite-if-exists | Écrase si le projet existe |
-s, --skip-if-file-exists | Ignore les fichiers existants |
-l, --list-installed | Liste les templates en cache |
--replay | Réutilise les réponses précédentes |
--accept-hooks | yes|ask|no pour les hooks |
Templates DevOps recommandés
Section intitulée « Templates DevOps recommandés »| Template | Description | Lien |
|---|---|---|
| cookiecutter-django | Django production-ready avec Docker | GitHub |
| cookiecutter-pypackage | Package Python avec tests et CI | GitHub |
| cookiecutter-ansible-role | Rôle Ansible avec molécule | GitHub |
| cookiecutter-flask | Flask avec API REST et Docker | GitHub |
Fichier de configuration utilisateur
Section intitulée « Fichier de configuration utilisateur »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 :
cookiecutter gh:audreyfeldroy/cookiecutter-pypackageFAQ : questions fréquentes
Section intitulée « FAQ : questions fréquentes »Les questions ci-dessous reprennent les points d'entrée du guide : ce qu'est réellement Cookiecutter, comment écrire son propre template, sa portée au-delà de Python, et son usage en CI/CD. Un point qu'elles ne couvrent pas et qui surprend souvent : un projet généré ne reste pas lié à son template. Cookiecutter fait une génération ponctuelle, aucune commande ne propage ensuite les évolutions du template vers les projets déjà créés.
cookiecutter.json, il pose quelques questions puis produit une structure de projet complète et cohérente, en substituant les variables avec Jinja2 ({{ cookiecutter.variable }}).cookiecutter.json (les variables et leurs valeurs par défaut) et un sous-dossier nommé avec une variable Jinja2, par exemple {{cookiecutter.project_name}}, qui contient les fichiers du projet. Les fichiers utilisent la syntaxe Jinja2, et on peut conditionner leur présence selon les réponses. On lance ensuite cookiecutter mon-template/.--no-input, qui utilise les valeurs par défaut du template sans poser de questions. On peut aussi passer des valeurs en ligne de commande (project_name="...") pour scripter entièrement la génération dans un pipeline. Un fichier ~/.cookiecutterrc permet de définir des valeurs par défaut globales.À retenir
Section intitulée « À retenir »- Cookiecutter = générateur de projets : une commande génère une structure complète
- Templates GitHub :
cookiecutter https://github.com/user/template - cookiecutter.json définit les variables et valeurs par défaut
- Jinja2 pour le contenu dynamique :
{{ cookiecutter.variable }} - Fichiers conditionnels : nommez
{{"Dockerfile" if var == "yes" else ""}} - Hooks : scripts Python exécutés avant/après génération
- --no-input pour les pipelines CI/CD
- ~/.cookiecutterrc pour vos valeurs par défaut globales