Shiny Apps as Desktop Apps

Turn an R Shiny app into an offline desktop application with Electron and shinylive, no server and no R install required.

r
shiny
electron
webassembly
desktop
Author

James Balamuta

Published

May 19, 2025

Abstract

Handing someone a Shiny app usually means handing them a running R server, which is the one thing most people cannot set up on their own. shinyelectron is an early experiment that takes another route: it compiles an R Shiny app to WebAssembly with shinylive and WebR, then wraps that build in an Electron shell to produce a standalone desktop installer for macOS, Windows, and Linux. The person you give it to installs one application, double-clicks it, and the app runs offline with no server and no R on their machine. This is a first look at something still rough around the edges, shared early because the core idea already works.

shinyelectron hex logo

shinyelectron hex logo

I build a fair number of Shiny apps, and a surprising number of them end the same way. The app works beautifully on my laptop, and then I have no clean way to hand it to the person who actually needs it. That gap is what shinyelectron is trying to close.

The problem with sharing a Shiny app

A Shiny app is a web application with an R process behind it. When you run one locally, R is quietly serving the page, reacting to inputs, and rerunning your reactive expressions on every click. That server is not optional. It is where the app actually lives.

This is fine when the audience is you, or a colleague who already has R and every package your app depends on. It gets awkward the moment you want to give the app to someone who does not live in R. You can deploy to shinyapps.io or stand up a Shiny Server, but now you are running infrastructure, thinking about accounts and uptime, and assuming the person has a network connection and permission to reach your server. For an internal tool, a teaching demo, or an app that has to work on a machine with no internet, none of that fits. What I have wanted for a long time is boring and specific: a file I can send someone, that they double-click, that just runs.

The idea: compile the app, then wrap it

Two pieces of technology make that file possible, and shinyelectron is mostly the glue between them.

The first is shinylive. shinylive takes a Shiny app and compiles it to run entirely in the browser using WebR, a build of R that runs as WebAssembly. There is no R server anymore. The R code, the packages, and the interpreter all ship as static assets and execute inside the browser itself. That already solves the hardest part of the problem, because the app no longer needs a running R process sitting on a server somewhere.

The second is Electron, the toolkit behind a lot of the desktop apps you already use every day. Electron bundles a browser and packages it as a native application for macOS, Windows, and Linux.

Put those together and the plan writes itself. Take the shinylive WebAssembly build of a Shiny app, drop it inside an Electron shell, and package the result as a desktop installer. The user installs an ordinary-looking application. Behind the window, it is a browser running your app as WebAssembly, offline, with no server and nothing to configure. Best of all, the person you hand it to does not need R installed at all.

A minimal export

The package is built around a single entry point, export(). You point it at the directory that holds your Shiny app and tell it where to put the result:

# install.packages("remotes")
remotes::install_github("coatless-rpkg/shinyelectron")

library(shinyelectron)

# appdir  = folder containing your app.R (or ui.R / server.R)
# destdir = where the packaged desktop app should be written
export(appdir = "my-shiny-app", destdir = "my-shiny-app-desktop")

That is the whole call. export() autodetects that appdir is an R Shiny app and defaults to the shinylive strategy, so a minimal export needs no other arguments. It runs the shinylive compilation, assembles the Electron project around it, and produces a desktop build you can install and run without R anywhere in sight.

The output is a real, native-feeling application. On macOS you get a .app, on Windows an installer, on Linux the usual packaged formats. Double-click it, and the app opens in its own window like anything else in your dock or start menu.

Where this is going

I want to be honest about the stage this is at. shinyelectron is early and a little experimental. It exports R Shiny apps through the shinylive strategy today, and that is the entire surface for now. The reason I am writing about it already is that the core idea works. I can take a Shiny app I built for myself and turn it into something I can email to a colleague, and it runs on their machine with nothing installed.

Because the shinylive path leans on WebAssembly, the same constraints WebR carries come along for the ride. Packages need to be available for WebR, and the app runs inside a browser sandbox rather than a full R installation. For a large and growing set of apps, that trade is well worth it in exchange for a download that just works.

There is a lot I want to build on top of this starting point, and I will write more here as those pieces land. For now, if you have a Shiny app gathering dust because you could never quite figure out how to give it to someone, point export() at it and see what comes out.

The code lives on GitHub, with documentation at the package site. It is released under AGPL (>= 3).

References