Gestion de versions Shiny : un workflow de déploiement Git + CI/CD
Faites survivre votre application à la modification d’un collègue, à un retour arrière et à une montée de version de dépendance — Git, renv et un déploiement automatisé.
Un workflow de déploiement reproductible et sûr pour une équipe, pour une application Shiny : placez-la sous Git avec un .gitignore adapté à Shiny, verrouillez les dépendances avec renv (validez renv.lock, jamais renv/library/), et automatisez le déploiement avec un pipeline CI/CD qui restaure les packages et publie à chaque push — avec les jetons de déploiement gardés dans les secrets CI, jamais dans le YAML.
- La gestion de versions est un outil de déploiement, pas seulement une sauvegarde. Git vous donne l’historique et une collaboration sûre ; le bénéfice est un déploiement reproductible et testé que vous déclenchez en poussant un commit.
- Un
.gitignoreShiny garde le dépôt propre et sûr. Excluezrenv/library/(volumineux, spécifique à la machine), les secrets (.Renviron,*.pem) et les métadonnées de déploiement (rsconnect/) — validez le code source et le fichier de verrouillage, rien d’autre. - Validez
renv.lock, jamaisrenv/library/. Le fichier de verrouillage enregistre les versions exactes des packages pour qu’un collègue — ou un runner CI — reconstruise la bibliothèque identique avecrenv::restore(). - Automatisez le déploiement avec CI/CD. Un court workflow GitHub Actions récupère le code, installe R, restaure
renv, et déploie à chaque push versmain— avec le jeton de déploiement lu depuis un secret de dépôt, jamais écrit dans le fichier. - The runtime is the judge. Quand un
git pushse termine par votre application en ligne à son URL sans que personne n’ait touché le serveur à la main, vous avez prouvé que le workflow fonctionne.
Introduction
Votre application fonctionne et elle est déployée — vous l’avez poussée sur shinyapps.io ou mise dans un conteneur. Maintenant, elle doit survivre à la vraie vie : un collègue la modifie la semaine prochaine, un changement casse quelque chose et il vous faut récupérer la version de mardi dernier, et dans six mois une mise à jour de package décale discrètement un résultat. Copier app_final_v2_REALLY.R sur un disque partagé ne survit à rien de tout cela.
Trois habitudes y remédient, et cette leçon consiste à les intégrer à votre déploiement — pas un tutoriel Git général :
- Git vous donne l’historique et la collaboration : chaque changement est enregistré, réversible et fusionnable au sein d’une équipe.
- renv vous donne la reproductibilité : un fichier de verrouillage épingle les versions exactes des packages, de sorte que l’application qui tournait sur votre portable est l’application qui tourne sur le serveur.
- CI/CD — intégration continue / déploiement continu, un pipeline automatisé qui s’exécute à chaque push — vous donne un déploiement reproductible et testé : fini le « quels fichiers ai-je téléversés la dernière fois ? »
Ensemble, elles transforment le déploiement d’un rituel manuel et sujet aux erreurs en une seule action : valider et pousser.
Il vous faut une application fonctionnelle et déployée à exploiter — si vous n’en avez pas, déployez sur shinyapps.io ou conteneurisez-la avec Docker d’abord (et construisez votre première application Shiny si vous débutez tout juste). Il vous faut aussi Git installé et un compte chez un hébergeur Git tel que GitHub ou GitLab — c’est sur cet hébergeur que s’exécute un pipeline CI/CD.
Les commandes et la configuration de cette page ne sont pas exécutées ici — les opérations Git, renv et un pipeline CI/CD agissent tous sur votre dépôt et votre compte, ce qu’une page web statique ne peut pas faire. Copiez n’importe quel bloc dans votre projet et exécutez-le là. Le vrai test, c’est ce qui se passe ensuite : un git push se termine par votre application en ligne à son URL, reconstruite depuis le fichier de verrouillage, sans étape manuelle. C’est la preuve que le workflow tient — the runtime is the judge.
Placez l’application sous Git — avec un .gitignore Shiny
Commencez par transformer le dossier de l’application en dépôt. Depuis le répertoire de l’application :
cd my-shiny-app
git init # start tracking this folder
git add . # stage the files (respecting .gitignore, below)
git commit -m "Initial commit: working Shiny app"Avant ce premier git add ., cependant, décidez de ce qui ne doit jamais entrer dans le dépôt. C’est le fichier le plus important de la gestion de versions d’un projet Shiny, et se tromper dessus, c’est ainsi que les dépôts gonflent à des gigaoctets ou divulguent un mot de passe. Créez un .gitignore à la racine de l’application :
# --- renv: commit the lockfile, NEVER the library ---
renv/library/ # machine-specific, huge — rebuilt from renv.lock
renv/local/
renv/cellar/
renv/staging/
# (renv.lock IS committed — it's the reproducibility record)
# --- secrets: never commit credentials ---
.Renviron # env vars, API keys, DB passwords
.env
*.pem # private keys / certificates
# --- deploy metadata (regenerated per environment) ---
rsconnect/
# --- R / RStudio cruft ---
.Rproj.user/
.Rhistory
.RData
.Ruserdata
# --- OS files ---
.DS_Store
Thumbs.db
# --- data you shouldn't ship (uncomment/adjust as needed) ---
# *.csv
# data/private/La règle qui piège la plupart des gens : validez renv.lock, pas renv/library/. Le dossier library/ contient les packages réellement installés — des centaines de mégaoctets de code compilé spécifique à votre système d’exploitation, inutile (et nuisible) sur la machine de quelqu’un d’autre. Le fichier de verrouillage est un petit fichier texte qui permet à n’importe quelle machine de reconstruire cette bibliothèque exactement. Ignorez le dossier, validez le fichier.
Les lignes de secrets comptent tout autant. Une clé .Renviron ou *.pem validée une seule fois vit dans votre historique pour toujours — même après l’avoir supprimée — alors gardez-les à l’écart dès le départ. (Les leçons shinyapps.io et Docker montrent où vont plutôt ces secrets : les variables d’environnement de la plateforme et les secrets de conteneur.)
Verrouillez les dépendances avec renv
Git versionne votre code ; il ne fait rien pour vos packages. « Ça marche sur ma machine » est presque toujours une différence de version — vous avez construit l’application avec ggplot2 3.5 et le serveur a installé la 3.4. renv comble cet écart en enregistrant les versions exactes que votre application utilise. Exécutez-le une fois dans le répertoire de l’application :
renv::init() # start tracking this project's packages
renv::snapshot() # write renv.lock with the exact versions you userenv::init() crée une bibliothèque privée au projet et scanne votre code à la recherche des appels library() ; renv::snapshot() écrit renv.lock — un fichier JSON listant chaque package et sa version précise. Validez ce fichier de verrouillage :
git add renv.lock
git commit -m "Lock dependencies with renv"Désormais, quiconque clone le dépôt — un collègue, ou le runner CI qui le déploie — exécute une seule commande pour reproduire votre environnement :
renv::restore() # install the exact versions from renv.lockC’est ce qui rend le dépôt reproductible : le fichier de verrouillage voyage avec le code, et chaque environnement se reconstruit à partir de lui. Réexécutez renv::snapshot() et validez le fichier de verrouillage mis à jour chaque fois que vous ajoutez ou mettez à niveau un package. (Les leçons de déploiement shinyapps.io et Docker utilisent toutes deux ce même fichier de verrouillage — ici, il alimente aussi le pipeline CI ci-dessous.)
Un flux sain de branche et de revue
Vous n’avez pas besoin d’un modèle de branchement élaboré pour une application Shiny. Gardez main toujours déployable, et faites le nouveau travail sur une branche éphémère :
git checkout -b feature/add-export-button # branch off main
# ... make changes, commit them ...
git push -u origin feature/add-export-buttonOuvrez ensuite une pull request (sur GitHub) ou une merge request (sur GitLab) — les deux sont la même idée : un changement proposé qu’un collègue examine avant qu’il ne rejoigne main. À la fusion, main avance et (avec le pipeline ci-dessous) se déploie tout seul. C’est toute la boucle : branche → PR/MR → revue → fusion → déploiement automatique. Résistez à l’envie de bâtir un processus de release multi-branches autour d’une seule application ; la concision paie en maux de tête de fusion évités.
Automatisez le déploiement avec CI/CD
Voici le bénéfice. Au lieu de penser à lancer deployApp() à la main après chaque changement, laissez votre hébergeur Git le faire. Sur GitHub, c’est GitHub Actions : les fichiers de workflow dans .github/workflows/ s’exécutent sur les événements que vous choisissez — ici, un push vers main.
La communauté R maintient des blocs prêts à l’emploi exactement pour cela dans r-lib/actions : setup-r installe R, et setup-renv restaure votre bibliothèque verrouillée. Créez .github/workflows/deploy.yml :
name: Deploy Shiny app
on:
push:
branches: [main] # deploy on every push to main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Check out the code
uses: actions/checkout@v4
- name: Set up R
uses: r-lib/actions/setup-r@v2
- name: Restore packages from renv.lock
uses: r-lib/actions/setup-renv@v2
- name: Deploy to shinyapps.io
env:
SHINYAPPS_NAME: ${{ secrets.SHINYAPPS_NAME }}
SHINYAPPS_TOKEN: ${{ secrets.SHINYAPPS_TOKEN }}
SHINYAPPS_SECRET: ${{ secrets.SHINYAPPS_SECRET }}
run: |
# rsconnect is a deploy-time tool — install it if it isn't already in renv.lock
if (!requireNamespace("rsconnect", quietly = TRUE)) install.packages("rsconnect")
rsconnect::setAccountInfo(
name = Sys.getenv("SHINYAPPS_NAME"),
token = Sys.getenv("SHINYAPPS_TOKEN"),
secret = Sys.getenv("SHINYAPPS_SECRET")
)
rsconnect::deployApp(appName = "my-shiny-app", forceUpdate = TRUE)
shell: Rscript {0}Lisez-le étape par étape — le fichier est du YAML (YAML Ain’t Markup Language, le format de configuration à base d’indentation qu’utilisent les outils CI) :
on: push: branches: [main]— le déclencheur. Chaque push versmaindémarre le job ; rien ne s’exécute sur les autres branches, donc votre travail de fonctionnalité ne se déploie pas.actions/checkout@v4— clone votre dépôt sur le runner pour que le workflow puisse voir les fichiers de votre application etrenv.lock.r-lib/actions/setup-r@v2— installe R sur le runner (documentation r-lib/actions).r-lib/actions/setup-renv@v2— litrenv.locket restaure les versions exactes des packages (documentation setup-renv) — c’est là que valider le fichier de verrouillage porte ses fruits.- L’étape de déploiement — lit trois valeurs depuis
env:et appellersconnect:setAccountInfo()autorise le runner à publier sur votre compte, puisdeployApp(forceUpdate = TRUE)empaquette l’application et met à jour le déploiement existant sur place.
Les versions d’actions ci-dessus (checkout@v4, r-lib/actions/*@v2) sont à jour au moment de la rédaction — épinglez-vous à la dernière en vérifiant le README de chaque action avant de la copier, car les versions majeures évoluent.
Puis la seule règle qui garde tout cela sûr : le jeton de déploiement n’apparaît jamais dans le YAML. La syntaxe ${{ secrets.* }} tire les valeurs depuis les secrets chiffrés de votre dépôt. Ajoutez-les une fois sous Settings → Secrets and variables → Actions → New repository secret (SHINYAPPS_TOKEN, SHINYAPPS_SECRET, SHINYAPPS_NAME) — GitHub les masque dans les logs et ne les expose jamais aux pull requests issues de forks (documentation des secrets GitHub Actions). Un jeton codé en dur dans deploy.yml est un jeton publié à quiconque peut lire le dépôt.
Vous voulez une vérification avant le déploiement ? Ajoutez une étape qui exécute vos tests (par exemple shiny::runTests() ou testthat::test_dir("tests")) avant l’étape de déploiement — si elle échoue, le job s’arrête et rien n’est livré. C’est la moitié « intégration continue » qui fait son travail.
GitLab a la même forme, juste un fichier différent : un .gitlab-ci.yml à la racine du dépôt, les secrets sous Settings → CI/CD → Variables, et — si vous déployez par conteneur plutôt que sur shinyapps.io — un job qui construit et pousse votre image Docker au lieu d’appeler rsconnect. Les éléments (restaurer renv, s’authentifier depuis un secret, déployer) ne changent pas ; seule la cible de déploiement change.
Quelle habitude fait quoi
| Habitude | Résout | La seule chose à retenir |
|---|---|---|
Git + .gitignore |
Historique, collaboration, retour arrière sûr | Validez le code source + renv.lock ; ignorez renv/library/ et les secrets |
| renv | Packages reproductibles entre machines | Validez le fichier de verrouillage ; renv::restore() le reconstruit |
| CI/CD | Un déploiement reproductible, testé, automatique | Déployez au push ; gardez les jetons dans les secrets CI, pas dans le YAML |
Ensemble, elles signifient qu’un changement est à un git push d’être en ligne — révisé, verrouillé en version, et déployé de la même façon à chaque fois.
Problèmes fréquents
Le dépôt a gonflé à des centaines de mégaoctets. Vous avez validé renv/library/ — les packages installés, pas seulement le fichier de verrouillage. Ajoutez renv/library/ à .gitignore, puis retirez-le du suivi avec git rm -r --cached renv/library/ et validez. Ne gardez que renv.lock ; la bibliothèque se reconstruit à partir de lui avec renv::restore().
Un secret a été validé. Un .Renviron, une clé d’API ou un *.pem s’est glissé dans un commit. Le supprimer dans un nouveau commit ne suffit pas — il reste dans l’historique. Renouvelez immédiatement l’identifiant (supposez qu’il est compromis), puis purgez-le de l’historique avec un outil comme git filter-repo ou le guide de suppression de secrets de GitHub, et forcez le push. Ajoutez le fichier à .gitignore pour que cela ne puisse plus se reproduire.
Le déploiement CI échoue sur un package manquant. Le runner a installé une version différente (ou aucune) d’un package dont l’application a besoin. Assurez-vous que renv.lock est validé et à jour (renv::snapshot() en local, puis validez), et que votre workflow le restaure (r-lib/actions/setup-renv@v2) avant l’étape de déploiement. Un déploiement qui saute renv::restore() déploie contre ce que le runner a installé par hasard.
Questions fréquentes
Validez renv.lock (ainsi que les petits renv/activate.R et .Rprofile que renv::init() crée) — c’est l’enregistrement de reproductibilité. Ne validez pas renv/library/ : ce sont les packages installés, spécifiques à la machine et souvent des centaines de mégaoctets, et c’est régénéré depuis le fichier de verrouillage par renv::restore(). Le .gitignore par défaut de renv exclut déjà le dossier de bibliothèque pour vous (documentation renv).
Excluez trois choses : renv/library/ (volumineux et spécifique à la machine — validez renv.lock à la place), les secrets (.Renviron, .env, *.pem, tout fichier d’identifiants) et les métadonnées de déploiement (rsconnect/). Ajoutez les habituels résidus R/RStudio (.Rproj.user/, .Rhistory, .RData) et les fichiers d’OS (.DS_Store). Validez le code source de votre application et le fichier de verrouillage ; ignorez tout ce qui est régénéré ou secret.
Ajoutez un workflow à .github/workflows/deploy.yml déclenché on: push vers main. Dedans : actions/checkout le code, r-lib/actions/setup-r pour installer R, r-lib/actions/setup-renv pour restaurer les packages depuis renv.lock, puis une étape Rscript qui appelle rsconnect::setAccountInfo() et rsconnect::deployApp(forceUpdate = TRUE). Lisez le jeton de compte depuis un secret de dépôt (${{ secrets.SHINYAPPS_TOKEN }}), jamais depuis le fichier lui-même (r-lib/actions).
Stockez-les comme secrets chiffrés chez votre hébergeur Git — GitHub : Settings → Secrets and variables → Actions ; GitLab : Settings → CI/CD → Variables — et référencez-les dans le workflow avec ${{ secrets.NAME }} (GitHub) ou le nom de la variable (GitLab). La plateforme CI les injecte à l’exécution et les masque dans les logs (documentation des secrets GitHub). Ne codez jamais en dur un jeton, un mot de passe ou une clé dans le YAML — quiconque peut lire le dépôt peut lire le fichier.
Oui — ils résolvent des problèmes différents. Git versionne votre code ; renv versionne vos packages. Sans fichier de verrouillage, un collègue ou un runner CI installe les versions de packages en vigueur ce jour-là, et une application qui fonctionnait le mois dernier peut casser sur une montée de version silencieuse. Validez renv.lock aux côtés de votre code pour que la source et ses dépendances exactes soient toutes deux reproductibles.
Testez vos connaissances
Vous configurez Git pour une application Shiny qui utilise renv et lit un mot de passe de base de données depuis un fichier .Renviron. Écrivez les trois lignes les plus importantes que votre .gitignore doit contenir — celles qui empêchent un dépôt gonflé et un secret divulgué — et dites pourquoi chacune compte.
Pensez à (1) le seul dossier renv que vous ne devez jamais valider tout en validant le fichier de verrouillage, (2) le fichier contenant votre mot de passe de base de données, et (3) le dossier de métadonnées de déploiement auto-généré.
renv/library/ # installed packages — huge, machine-specific; rebuilt from renv.lock
.Renviron # holds the database password / API keys — never commit a secret
rsconnect/ # deploy metadata, regenerated per environmentrenv/library/ garde des centaines de mégaoctets de packages spécifiques à l’OS hors du dépôt — vous validez le petit renv.lock à la place, et renv::restore() reconstruit la bibliothèque n’importe où. .Renviron garde votre mot de passe de base de données hors de l’historique (un secret validé reste dans l’historique même après suppression, il ne doit donc jamais y entrer). rsconnect/ est de la comptabilité de déploiement recréée par environnement et n’a pas sa place dans le contrôle de version. Validez le code de votre application et renv.lock ; ignorez ceux-ci.
Votre workflow GitHub Actions a besoin de votre jeton shinyapps.io pour déployer. Où le jeton doit-il aller ?
A. Collé directement dans deploy.yml pour que le workflow puisse le lire.
B. Dans un secret de dépôt, référencé comme ${{ secrets.SHINYAPPS_TOKEN }} dans le workflow.
C. Validé dans le dépôt dans un fichier tokens.R que le workflow charge.
D. Affiché dans le log CI au début du job pour que vous puissiez le vérifier.
B. Stockez le jeton comme secret de dépôt chiffré (Settings → Secrets and variables → Actions) et référencez-le avec ${{ secrets.SHINYAPPS_TOKEN }} ; la plateforme l’injecte à l’exécution et le masque dans les logs. A et C valident tous deux le secret dans le dépôt — quiconque peut lire le code peut voler le jeton, et il vit dans l’historique pour toujours. D le divulgue délibérément dans les logs. Un identifiant de déploiement a sa place dans les secrets CI, jamais dans un fichier ou un log.
Conclusion
La gestion de versions d’une application Shiny déployée, ce sont trois habitudes qui fonctionnent ensemble, pas une dissertation sur Git. Placez l’application sous Git avec un .gitignore qui exclut renv/library/ et chaque secret — validez le code source et renv.lock, rien d’autre. Verrouillez les dépendances avec renv pour que n’importe quelle machine reconstruise votre bibliothèque exacte depuis le fichier de verrouillage. Puis laissez un pipeline CI/CD restaurer cette bibliothèque et déployer à chaque push vers main, en lisant son jeton depuis un secret CI plutôt que depuis le YAML. Le résultat est un déploiement que vous déclenchez d’un seul git push : révisé, verrouillé en version, et identique à chaque fois — et quand l’application apparaît à son URL sans étape manuelle, le runtime a prouvé que le workflow fonctionne.
Leçons connexes
- Déployer, puis exploiter : déployer sur shinyapps.io et conteneuriser avec Docker sont les cibles de déploiement que ce pipeline pilote, et ajouter une connexion avec l’authentification protège l’application une fois en ligne. Nouveau sur Shiny ? Construire votre première application Shiny, c’est là que l’application commence.
- Aller plus loin : Applications web Shiny — tout le cursus Shiny. · Science computationnelle et IA — le pilier.
Prouvez que vous savez le faire. Maîtrisez toute la série Shiny en production — suivez votre parcours, construisez des projets et obtenez un certificat.
Passez à Pro — Prova illimité sur vos propres données et un certificat vérifiable qui atteste la compétence.
dès 15 $/mois facturé annuellement
✓ Vous êtes Pro — continuez. The runtime is the judge.
Réutilisation
Citation
@online{2026,
author = {},
title = {Gestion de versions Shiny : un workflow de déploiement Git +
CI/CD},
date = {2026-07-16},
url = {https://www.datanovia.com/learn/programming/shiny/production/version-control},
langid = {fr}
}