scaffold-shiny-app
About
This skill scaffolds new Shiny applications in R with three framework options: golem for production R packages, rhino for enterprise projects, or vanilla for quick prototypes. It handles project initialization and creates the first module structure. Use it when starting any interactive web application, dashboard, or data explorer in R that requires a structured foundation.
Quick Install
Claude Code
Recommendednpx skills add pjt222/agent-almanac -a claude-code/plugin add https://github.com/pjt222/agent-almanacgit clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/scaffold-shiny-appCopy and paste this command in Claude Code to install this skill
Documentation
Scaffold Shiny App
Make new Shiny app with prod-ready structure. Use golem, rhino, or vanilla scaffolding.
When Use
- Start new interactive web app in R
- Make dashboard or data explorer prototype
- Set up prod Shiny app as R package (golem)
- Bootstrap enterprise Shiny project (rhino)
Inputs
- Required: App name
- Required: Framework choice (golem, rhino, vanilla)
- Optional: Module scaffolding (default: yes)
- Optional: renv for dep management (default: yes)
- Optional: Deploy target (shinyapps.io, Posit Connect, Docker)
Steps
Step 1: Choose Framework
Judge project needs to pick framework.
| Framework | Best For | Structure |
|---|---|---|
| golem | Production apps shipped as R packages | R package with DESCRIPTION, tests, vignettes |
| rhino | Enterprise apps with JS/CSS build pipeline | box modules, Sass, JS bundling, rhino::init() |
| vanilla | Quick prototypes and learning | Single app.R or ui.R/server.R pair |
Got: Clear framework decision based on scope, team needs.
If fail: Unsure? Default to golem — most structure, can simplify later. Vanilla only for throwaway prototypes.
Step 2: Scaffold Project
Golem Path
golem::create_golem("myapp", package_name = "myapp")
Creates.
myapp/
├── DESCRIPTION
├── NAMESPACE
├── R/
│ ├── app_config.R
│ ├── app_server.R
│ ├── app_ui.R
│ └── run_app.R
├── dev/
│ ├── 01_start.R
│ ├── 02_dev.R
│ ├── 03_deploy.R
│ └── run_dev.R
├── inst/
│ ├── app/www/
│ └── golem-config.yml
├── man/
├── tests/
│ ├── testthat.R
│ └── testthat/
└── vignettes/
Rhino Path
rhino::init("myapp")
Creates.
myapp/
├── app/
│ ├── js/
│ ├── logic/
│ ├── static/
│ ├── styles/
│ ├── view/
│ └── main.R
├── tests/
│ ├── cypress/
│ └── testthat/
├── .github/
├── app.R
├── dependencies.R
├── rhino.yml
└── renv.lock
Vanilla Path
Create app.R.
library(shiny)
library(bslib)
ui <- page_sidebar(
title = "My App",
sidebar = sidebar(
sliderInput("n", "Sample size", 10, 1000, 100)
),
card(
card_header("Output"),
plotOutput("plot")
)
)
server <- function(input, output, session) {
output$plot <- renderPlot({
hist(rnorm(input$n), main = "Random Normal")
})
}
shinyApp(ui, server)
Got: Project dir made with all scaffolding files.
If fail: Golem? Ensure golem package installed: install.packages("golem"). Rhino? Install from GitHub: remotes::install_github("Appsilon/rhino"). Vanilla? Ensure shiny + bslib installed.
Step 3: Configure Dependencies
Golem/Vanilla
# Initialize renv
renv::init()
# Add core dependencies
usethis::use_package("shiny")
usethis::use_package("bslib")
usethis::use_package("DT") # if using data tables
usethis::use_package("plotly") # if using interactive plots
# Snapshot
renv::snapshot()
Rhino
Deps managed in dependencies.R.
# dependencies.R
library(shiny)
library(bslib)
library(DT)
Got: All deps recorded in DESCRIPTION (golem) or dependencies.R (rhino), locked with renv.
If fail: renv::init() fails? Check write perms. Packages fail to install? Check R version compat.
Step 4: Create First Module
Golem
golem::add_module(name = "dashboard", with_test = TRUE)
Creates R/mod_dashboard.R and tests/testthat/test-mod_dashboard.R.
Rhino
Make app/view/dashboard.R.
box::use(
shiny[moduleServer, NS, tagList, h3, plotOutput, renderPlot],
)
#' @export
ui <- function(id) {
ns <- NS(id)
tagList(
h3("Dashboard"),
plotOutput(ns("plot"))
)
}
#' @export
server <- function(id) {
moduleServer(id, function(input, output, session) {
output$plot <- renderPlot({
plot(1:10)
})
})
}
Vanilla
Add module functions to separate file R/mod_dashboard.R.
dashboardUI <- function(id) {
ns <- NS(id)
tagList(
h3("Dashboard"),
plotOutput(ns("plot"))
)
}
dashboardServer <- function(id) {
moduleServer(id, function(input, output, session) {
output$plot <- renderPlot({
plot(1:10)
})
})
}
Got: Module file made with UI + server functions using proper namespacing.
If fail: Ensure module uses NS(id) for all input/output IDs in UI function. Without namespacing, IDs collide when module used multiple times.
Step 5: Run Application
# Golem
golem::run_dev()
# Rhino
shiny::runApp()
# Vanilla
shiny::runApp("app.R")
Got: App launches in browser without errors.
If fail: Check R console for error msgs. Common: missing packages (install), port in use (specify different port port = 3839), syntax errors in UI/server.
Checks
- App dir has correct structure for chosen framework
-
shiny::runApp()launches without errors - At least one module scaffolded with UI + server functions
- Deps recorded (DESCRIPTION or dependencies.R)
- renv.lock captures all package versions
- Module uses
NS(id)for proper namespace isolation
Pitfalls
- Choose vanilla for prod: Vanilla lacks testing, docs, deploy tooling. Use golem or rhino for anything beyond prototypes.
- Missing namespace in modules: Every
inputIdandoutputIdin module UI must be wrapped withns(). Forget = silent ID collisions. - golem without devtools workflow: golem apps are R packages. Use
devtools::load_all(),devtools::test(),devtools::document()— notsource(). - rhino without box: rhino uses box for module imports. Do not fall back to
library()calls — usebox::use()for explicit imports.
See Also
build-shiny-module— make reusable Shiny modules with proper namespace isolationtest-shiny-app— set up shinytest2 and testServer() testsdeploy-shiny-app— deploy to shinyapps.io, Posit Connect, Dockerdesign-shiny-ui— bslib theming + responsive layout designcreate-r-package— R package scaffolding (golem apps are R packages)manage-renv-dependencies— detailed renv dep management
GitHub Repository
Related Skills
content-collections
MetaThis skill provides a production-tested setup for Content Collections, a TypeScript-first tool that transforms Markdown/MDX files into type-safe data collections with Zod validation. Use it when building blogs, documentation sites, or content-heavy Vite + React applications to ensure type safety and automatic content validation. It covers everything from Vite plugin configuration and MDX compilation to deployment optimization and schema validation.
polymarket
MetaThis skill enables developers to build applications with the Polymarket prediction markets platform, including API integration for trading and market data. It also provides real-time data streaming via WebSocket to monitor live trades and market activity. Use it for implementing trading strategies or creating tools that process live market updates.
creating-opencode-plugins
MetaThis skill helps developers create OpenCode plugins that hook into 25+ event types like commands, files, and LSP operations. It provides the plugin structure, event API specifications, and implementation patterns for JavaScript/TypeScript modules. Use it when you need to intercept, monitor, or extend the OpenCode AI assistant's lifecycle with custom event-driven logic.
sglang
MetaSGLang is a high-performance LLM serving framework that specializes in fast, structured generation for JSON, regex, and agentic workflows using its RadixAttention prefix caching. It delivers significantly faster inference, especially for tasks with repeated prefixes, making it ideal for complex, structured outputs and multi-turn conversations. Choose SGLang over alternatives like vLLM when you need constrained decoding or are building applications with extensive prefix sharing.
