Introducing {shinyfa}: A Developer Experience Boost for Shiny Apps
I’m thrilled to share a new R package I’ve been working on: {shinyfa}
— short for Shiny File Analysis. This package is designed to enhance the developer experience (DX) for folks working with large, complex Shiny applications.
🔗 GitHub: dalyanalytics/shinyfa
Why {shinyfa}
?
If you’ve ever joined a project with a sprawling Shiny codebase—hundreds of files, deeply nested folders, and server logic scattered across modules—you know how daunting it can be just to figure out where to start.
For consultants, new hires, or contributors onboarding to a project, {shinyfa}
provides an immediate overview of what the app is doing, and where.
What Does It Do?
{shinyfa}
inspects a given Shiny app directory and extracts key file-level information, including:
render*()
functions (likerenderPlot
,renderTable
,renderUI
, etc.)reactive()
,observe()
,observeEvent()
and other reactive componentsInput bindings like
input$
used within the app
It then returns a structured, tidy data.frame
(or tibble) summarizing where these elements appear in your app. This gives you a searchable, sortable, filterable bird’s-eye view of the logic powering your application.
Who Is This For?
This package is especially useful for:
🌅 Consultants jumping into existing client projects
🧭 Internal dev teams who want a clearer map of how their app works
🌱 New team members onboarding to a complex Shiny product
👩💻 Tech leads looking to identify opportunities for refactoring or optimization
Even if your app is nicely modularized, {shinyfa}
can still save time by giving you a summary of reactive logic at a glance.
How to Get Started
Install the package from GitHub using {pak}:
# install.packages("pak")
pak::pak("dalyanalytics/shinyfa")
Then run it on a Shiny app directory:
library(shinyfa)
library(dplyr)
file_path_df <- list.files("SHINY-SERVER-DIRECTORY",
pattern = "\\.R$", full.names = TRUE)
file_analysis <- data.frame() # Initialize an empty dataframe
for (file in file_path_df) {
shiny_analysis <- analyze_shiny_reactivity(file_path = file)
# Skip if NULL (empty file or only `source()` calls)
if (is.null(shiny_analysis)) next
# Add filename column
shiny_analysis$file_name <- basename(file)
# Bind results
file_analysis <- bind_rows(file_analysis, shiny_analysis)
}
print(file_analysis)
Help Improve {shinyfa}
!
This is an early-stage, in-progress package—and I’d love your help making it better. If you try it out and have suggestions, please:
Open a discussion or issue
Send a pull request
Share it with your network!