Structure d’une application Shiny : ui, server et le fichier app.R expliqués

L’anatomie de chaque application Shiny — deux moitiés, un fichier, et les ids qui les relient.

Programming
Shiny

Chaque application Shiny est un ui (ce que l’utilisateur voit) et un server (la logique R), reliés par shinyApp(). Découvrez comment une application est organisée : le fichier app.R unique, comment les input/output ids relient le ui au server, quand séparer en ui.R + server.R, global.R pour la configuration partagée, et l’organisation du dossier de projet (www/, R/, data/).

Date de publication

28 juin 2026

Modifié

7 juillet 2026

AstucePoints clés
  • Chaque application a deux moitiés : un ui (ce que l’utilisateur voit) et un server (la logique R), reliés par shinyApp(ui, server).
  • Un seul fichier suffit. Placez les trois dans un fichier nommé app.R — c’est la structure canonique et le point de départ de chaque application.
  • Les ids sont le câblage. Un inputId dans le ui est lu dans le server comme input$<id> ; un emplacement outputId est rempli par output$<id>. La correspondance des noms est toute la connexion.
  • Séparez en ui.R + server.R uniquement quand un seul fichier devient ingérable ; tournez-vous vers global.R pour charger données et fonctions auxiliaires une seule fois, partagées par les deux.
  • Un vrai projet est un dossierapp.R (ou le trio) plus www/ pour les ressources, R/ pour les fonctions auxiliaires, et data/ pour les fichiers.

Introduction

Vous avez installé Shiny et vous êtes prêt à construire. Avant d’écrire la moindre ligne d’interface utilisateur, vous devez savoir comment une application est organisée — où va la mise en page, où va votre code R, et comment les deux dialoguent entre eux.

La structure est petite et fixe. Chaque application Shiny, d’une démo de dix lignes à un tableau de bord de production, ce sont les mêmes deux pièces — un ui et un server — plus un appel qui les lance. Maîtrisez cette forme et le reste de la série ne fait que la remplir. Cette leçon expose l’anatomie : le fichier app.R unique, le contrat d’id qui relie les entrées aux sorties, quand séparer en deux fichiers, et le dossier dans lequel vit un vrai projet.

Les deux moitiés : ui et server

Une application Shiny est construite à partir d’exactement deux objets.

Le ui — ce que l’utilisateur voit. Un appel imbriqué de fonctions de mise en page (fluidPage(), sidebarLayout(), …) qui place les entrées (curseurs, listes déroulantes, boutons) et les emplacements de sortie (un graphique ici, un tableau là). Il décrit la page, pas la logique.

Le server — ce que fait R. Une fonction de signature function(input, output, session). Elle lit les valeurs d’entrée courantes et construit les sorties que le ui affiche. C’est là que vit votre analyse.

Un troisième appel, shinyApp(ui, server), relie les deux moitiés et lance l’application. C’est tout le contrat :

library(shiny)

ui <- fluidPage(
  # inputs and output slots go here
)

server <- function(input, output, session) {
  # read input$..., write output$...
}

shinyApp(ui = ui, server = server)

Enregistrez ces trois blocs dans un seul fichier et vous avez une application exécutable.

Le fichier canonique : app.R

La structure standard est un fichier unique nommé app.R qui contient les trois parties dans l’ordre : charger le package, définir ui, définir server, puis appeler shinyApp(). Le nom a son importance — RStudio reconnaît un fichier nommé app.R et affiche un bouton Run App, et les plateformes d’hébergement le cherchent par son nom.

Voici un app.R complet. Il utilise le jeu de données intégré faithful de R (temps d’attente entre éruptions), il tourne donc avec pour seule installation le package shiny :

# app.R
library(shiny)

# 1. ui — what the user sees
ui <- fluidPage(
  titlePanel("Old Faithful eruptions"),
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins", "Number of bins:",
                  min = 1, max = 50, value = 30)
    ),
    mainPanel(
      plotOutput("distPlot")
    )
  )
)

# 2. server — the R logic
server <- function(input, output, session) {
  output$distPlot <- renderPlot({
    x    <- faithful$waiting
    bins <- seq(min(x), max(x), length.out = input$bins + 1)
    hist(x, breaks = bins, col = "#3a86d4", border = "white",
         xlab = "Waiting time to next eruption (min)", main = "")
  })
}

# 3. launch
shinyApp(ui = ui, server = server)

Les trois sections numérotées sont toujours présentes et toujours dans cet ordre. L’argument session dans la signature du server est optionnel dans l’ancien code mais standard désormais — incluez-le ; les fonctionnalités ultérieures (mise à jour des entrées, nettoyage de session) en ont besoin.

NoteCopiez n’importe quel bloc dans app.R et exécutez-le en local

Le code de cette page n’est pas exécuté ici — une application Shiny a besoin d’une session R active, elle ne peut donc pas tourner dans une page web statique. Copiez n’importe quel bloc dans un fichier app.R et exécutez-le en local avec shiny::runApp() (ou cliquez sur Run App dans RStudio) pour le voir fonctionner. Chaque exemple est autonome et n’utilise que des données intégrées.

Comment input$ et output$ relient les moitiés

Le ui et le server sont des objets séparés — ils ne s’appellent jamais directement l’un l’autre. Ils sont câblés ensemble par la correspondance des ids, et ce câblage est l’idée la plus importante de la structure.

Chaque contrôle d’entrée prend un inputId comme premier argument. Le server lit cette valeur via input$<id>le même nom. Dans l’application ci-dessus, le curseur est déclaré sliderInput("bins", …), donc sa valeur est lue comme input$bins :

# ui side — declare an input with an id
sliderInput("bins", "Number of bins:", min = 1, max = 50, value = 30)

# server side — read it by the SAME id
output$distPlot <- renderPlot({
  bins <- seq(min(x), max(x), length.out = input$bins + 1)  # input$bins
  # ...
})

Les sorties fonctionnent de la même façon, à l’envers. Le ui réserve un emplacement avec un outputId (par ex. plotOutput("distPlot")), et le server remplit ce nom exact via output$<id> :

# ui side — reserve a slot with an id
plotOutput("distPlot")

# server side — fill the SAME id
output$distPlot <- renderPlot({ ... })

Le contrat, ce sont donc deux paires de chaînes correspondantes : inputId ↔︎ input$id, et outputId ↔︎ output$id. Faites concorder les noms et Shiny les relie à votre place. Une faute de frappe dans l’un ou l’autre id rompt silencieusement le lien — l’entrée se lit comme NULL, ou l’emplacement de sortie reste vide, sans aucune erreur.

Cette connexion automatique — une entrée change, la sortie qui en dépend se recalcule — c’est la réactivité, le moteur de chaque application Shiny. La structure, c’est ce que vous câblez ; la réactivité, c’est ce qui rend ce câblage vivant. La leçon sur la réactivité explique son fonctionnement en profondeur.

Un fichier ou deux : app.R vs ui.R + server.R

app.R n’est pas la seule organisation. Shiny reconnaît aussi une structure à deux fichiers : un ui.R qui définit ui et un server.R qui définit server, tous deux dans le même dossier. Il n’y a pas d’appel à shinyApp() dans la forme à deux fichiers — Shiny trouve les deux fichiers par leur nom et les relie lui-même.

# ui.R
library(shiny)

fluidPage(
  titlePanel("Old Faithful eruptions"),
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins", "Number of bins:", min = 1, max = 50, value = 30)
    ),
    mainPanel(plotOutput("distPlot"))
  )
)
# server.R
library(shiny)

function(input, output, session) {
  output$distPlot <- renderPlot({
    x    <- faithful$waiting
    bins <- seq(min(x), max(x), length.out = input$bins + 1)
    hist(x, breaks = bins, col = "#3a86d4", border = "white", main = "")
  })
}

Remarquez que la forme à deux fichiers abandonne les affectations et le lancement : ui.R se termine par l’objet fluidPage(...) lui-même, et server.R se termine par la function(...) nue. Shiny les lit et exécute l’application.

Lequel utiliser ?

Utilisez… Quand
Un seul app.R La plupart des applications. Tout ce que vous pouvez parcourir confortablement, prototypes, exemples, partage d’un seul fichier.
ui.R + server.R Le fichier devient long et vous voulez la mise en page et la logique à des endroits séparés.

Commencez chaque application par un seul app.R. Séparez-la en deux fichiers seulement une fois qu’un seul fichier devient ingérable — les applications sont par ailleurs identiques, et vous pouvez basculer plus tard sans rien réécrire.

global.R : configuration partagée, exécutée une seule fois

Les deux structures peuvent inclure un global.R optionnel dans le même dossier. Shiny l’exécute une seule fois au démarrage de l’application (pas par utilisateur), et tout ce qu’il définit est visible à la fois par ui et server. C’est l’endroit pour le travail que vous ne voulez pas répéter : charger les packages, lire un jeu de données, définir des constantes et des fonctions auxiliaires.

# global.R — run once at startup, shared by ui and server
library(shiny)
library(ggplot2)

# load data once (shared across all users)
trees_data <- read.csv("data/trees.csv")

# constants and helpers available everywhere
APP_TITLE <- "Tree Survey"
source("R/plotting.R")

Charger un grand jeu de données à l’intérieur du server le rechargerait pour chaque session utilisateur ; dans global.R, il se charge une seule fois et tout le monde le partage. Ce simple geste est la correction de performance la plus courante pour une application au démarrage lent.

L’organisation du dossier de projet

Une application jetable, c’est un fichier. Un vrai projet est un dossier — le fichier de l’application (ou le trio) plus les répertoires que Shiny connaît par convention :

my-app/
├── app.R          # or: ui.R + server.R
├── global.R       # optional: shared setup, run once at startup
├── R/             # helper functions, sourced in global.R
│   └── plotting.R
├── data/          # data files the app reads
│   └── trees.csv
└── www/           # static web assets, served at the app's root URL
    ├── style.css
    └── logo.png

Trois conventions méritent d’être connues dès maintenant :

  • www/ — tout ce qui s’y trouve est servi comme fichier statique à la racine web de l’application. Un logo dans www/logo.png est référencé dans le ui comme "logo.png" (sans préfixe www/). C’est là que vont le CSS, les images et le JavaScript.
  • R/ — placez les fonctions auxiliaires dans des fichiers .R ici et faites-les source() depuis global.R pour garder le fichier de l’application centré sur la structure, pas sur les utilitaires.
  • data/ — gardez les fichiers de données ensemble et lisez-les (généralement dans global.R) avec un chemin relatif comme "data/trees.csv".

Vous n’avez besoin d’aucun de ces éléments dès le premier jour — un seul app.R est une application complète. Ajoutez les dossiers à mesure que le projet grandit.

Problèmes fréquents

Une entrée se lit comme NULL, ou un emplacement de sortie reste vide. La chaîne inputId/outputId et le nom input$/output$ ne correspondent pas. sliderInput("bins", …) se lit comme input$bins — exactement la même orthographe, casse comprise. Une faute de frappe d’un côté ou de l’autre rompt le lien silencieusement, sans aucun message d’erreur.

« Could not find function shinyApp » / rien ne se lance. Dans une application à fichier unique, vous devez terminer app.R par shinyApp(ui = ui, server = server) — sans cela, le ui et le server ne sont que des objets et aucune application ne démarre. (Dans la forme à deux fichiers ui.R/server.R, il n’y a pas d’appel à shinyApp() — Shiny le fournit.)

Error in server: unused argument / l’application refuse de démarrer. Le server doit être une fonction dont les arguments sont input, output, session dans cet ordre. Écrire function(output, input) (inversé) ou omettre les parenthèses rompt le contrat attendu par Shiny.

Questions fréquentes

Utilisez un seul app.R pour presque tout — c’est la structure canonique et elle garde toute l’application au même endroit. Passez à des fichiers ui.R et server.R séparés seulement quand un seul fichier devient assez long pour que vous préfériez lire la mise en page et la logique séparément. Les applications sont par ailleurs identiques, vous pouvez donc les séparer plus tard sans rien réécrire.

shinyApp(ui, server) combine les deux moitiés de votre application et renvoie un objet application exécutable. Dans une application à fichier unique app.R, vous l’appelez en dernière ligne pour lancer l’application. Dans la structure à deux fichiers ui.R/server.R, vous ne l’appelez pas du tout — Shiny relie les fichiers lui-même.

Par la correspondance des ids. Chaque entrée a un inputId (par ex. sliderInput("bins", …)) que le server lit comme input$bins — le même nom. Chaque sortie a un emplacement outputId (par ex. plotOutput("distPlot")) que le server remplit comme output$distPlot. Les chaînes doivent correspondre exactement ; cet appariement est toute la connexion entre les deux moitiés.

global.R contient la configuration qui doit s’exécuter une seule fois au démarrage de l’application et être partagée à la fois par ui et server — charger les packages, lire un jeu de données, définir des constantes et des fonctions auxiliaires. Charger les données ici (plutôt qu’à l’intérieur du server) signifie qu’elles se chargent une seule fois pour tous les utilisateurs au lieu d’une fois par session.

www/ est le répertoire des ressources web statiques — CSS, images, JavaScript, polices. Les fichiers qu’il contient sont servis à la racine de l’application, donc une image dans www/logo.png est référencée dans le ui simplement comme "logo.png", sans préfixe www/.

Testez vos connaissances

Vous voulez une zone de texte où l’utilisateur saisit un titre, et un graphique qui utilise ce titre. Le ui les déclare ainsi :

ui <- fluidPage(
  textInput("plot_title", "Plot title:"),
  plotOutput("hist")
)

Écrivez la fonction server correspondante : remplissez l’emplacement du graphique avec un histogramme de faithful$waiting, en utilisant le texte saisi comme titre principal du graphique.

L’inputId est "plot_title", lisez-le donc comme input$plot_title. L’outputId est "hist", affectez donc à output$hist. Enveloppez le code de tracé dans renderPlot({ ... }) et passez l’entrée à hist(..., main = ...).

server <- function(input, output, session) {
  output$hist <- renderPlot({
    hist(faithful$waiting,
         main = input$plot_title,
         col  = "#3a86d4", border = "white")
  })
}

Les noms concordent : output$hist remplit plotOutput("hist"), et input$plot_title lit textInput("plot_title", …). Comme le graphique lit input$plot_title, il se redessine dès que l’utilisateur modifie le titre — c’est la réactivité qui fait le câblage à votre place.

Quelle affirmation à propos de la structure d’une application Shiny est correcte ?

A. Une application à fichier unique doit être nommée main.R. B. Dans une application à fichier unique, shinyApp(ui, server) est la dernière ligne qui lance l’application. C. Un inputId dans le ui et le nom input$ dans le server peuvent différer. D. global.R s’exécute une fois par session utilisateur.

B. Une application à fichier unique se termine par shinyApp(ui, server) pour se lancer. A est faux — le fichier doit être nommé app.R. C est faux — les ids doivent correspondre exactement, sinon la connexion est rompue. D est faux — global.R s’exécute une seule fois au démarrage de l’application, partagé par toutes les sessions, pas une fois par utilisateur.

Conclusion

Chaque application Shiny a la même forme : un ui pour la page, un server pour la logique R, reliés par shinyApp(), avec les ids input$/output$ qui câblent les deux moitiés ensemble. La plupart des applications vivent dans un seul app.R ; séparez en ui.R + server.R quand elle grandit, déplacez la configuration partagée dans global.R, et laissez un vrai projet s’étendre dans www/, R/ et data/. Voilà toute l’anatomie — ensuite, vous construirez une application fonctionnelle à partir d’un fichier vierge.

Leçons connexes

Cette page vous a-t-elle été utile ?

Recevez les nouvelles leçons R & Python par e-mail

Pratique, reproductible, sans spam. Désinscription à tout moment.

Double opt-in. Nous ne partageons jamais votre e-mail.

Partager cette pageXLinkedInRedditHN

Réutilisation

Citation

BibTeX
@online{2026,
  author = {},
  title = {Structure d’une application Shiny : ui, server et le fichier
    app.R expliqués},
  date = {2026-06-28},
  url = {https://www.datanovia.com/learn/programming/shiny/foundations/app-structure},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“Structure d’une application Shiny : ui, server et le fichier app.R expliqués.” 2026. June 28. https://www.datanovia.com/learn/programming/shiny/foundations/app-structure.