Run Shiny Apps Locally
Tags: shiny, rstats
Published: 2021-04-25 20:36:47

<p><em>By: <a href='https://hosting.analythium.io/author/peter/'>Peter Solymos</a></em></p><p>You might be eager to deploy your Shiny app to a remote server. But the simplest way to run a Shiny app is to run it locally. You only need the <strong>shiny</strong> R package installed, and you can run the app in your browser. In this post you'll see a few ways of <strong>how to organize your files</strong> to be served locally. Why bother reviewing all this? Well, as you will see in subsequent posts, this is the foundation for all the other kinds of hosting options.</p><h2 id="why-run-shiny-locally">Why run Shiny locally</h2><p>There are a couple of reasons why running Shiny apps locally is necessary. First and foremost, that is how you can <strong>test the app</strong> if you are the developer. Of course testing goes way beyond just opening up the app, read more about best practices for engineering Shiny apps in this <a href="https://engineering-shiny.org/build-yourself-safety-net.html">excellent book</a> written by <a href="https://thinkr.fr/">ThinkR</a> folks.</p><p>The source code for the app can be <strong>shared</strong> with collaborators, clients, and users. They can run the app themselves if they are R savvy enough. When the audiences of a Shiny app are R users, it makes sense to <a href="https://shiny.rstudio.com/articles/deployment-local.html">share the app</a> as a Gist, GitHub repository, or a zip file. However, sharing Shiny apps this way leaves installing dependencies up to the user.</p><p>Distributing Shiny apps as <a href="https://mastering-shiny.org/scaling-packaging.html">part of an R package</a> takes care of dependency management. Putting your <strong>Shiny app inside an R package</strong> is especially useful when the app is used to augment the command line capabilities of the package. In such cases, the Shiny apps are often <a href="https://shiny.rstudio.com/articles/function.html">included in functions</a>, i.e. <code>somepackage::run_app()</code>. </p><p>The most important reason for reviewing how to run Shiny apps locally is that the practices that let you run the Shiny app locally are the same practices you can use when <strong>deploying your apps to remote servers</strong>. So let's review the options!</p><h2 id="how-to-run-shiny-locally">How to run Shiny locally</h2><p>In a <a href="https://hosting.analythium.io/the-anatomy-of-a-shiny-application">previous post</a> you have seen how a Shiny app is structured. Besides being just an HTML file at the end, it requires the websocket server in the background to constantly update the application state when the user interacts with the web page. Therefore, we cannot just copy the HTML output to a server, like we would with a static website.</p>
<h3 id="single-file">Single file</h3><p>Let's take the following file named <code>app.R</code>:</p><pre><code class="language-R">library(shiny)
ui &lt;- fluidPage(
    mainPanel(
        sliderInput("obs",
            "Number of observations",
            min = 1,
            max = 5000,
            value = 100),
        plotOutput("distPlot")
    )
)
server &lt;- function(input, output) {
    output$distPlot &lt;- renderPlot({
        dist &lt;- rnorm(input$obs)
        hist(dist,
            col="purple",
            xlab="Random values")
    })
}
shinyApp(ui = ui, server = server)</code></pre><p>If you are using the <a href="https://www.rstudio.com/products/rstudio/">RStudio IDE</a>, you should see the <strong>Run App</strong> button:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://hosting.analythium.io/content/images/2021/04/Screen-Shot-2021-04-02-at-6.25.53-PM.png" class="kg-image" alt="Run Shiny app from RStudio IDE" loading="lazy" width="1326" height="822"><figcaption>Run Shiny app from RStudio IDE</figcaption></figure><p>Clicking on the button would run the app. If you inspect the console output, you should see something like this:</p><pre><code class="language-bash">&gt; runApp('~/your/path')

Listening on http://127.0.0.1:3884</code></pre><p>What does this mean? Pushing the Run App button led to running the <code>runApp()</code> command. This started the local server (127.0.0.1 is also called the local host) listening on port 3884 (your port number might be different). If you visit the http://127.0.0.1:3884 address in your browser, you should see the Shiny app with the slider and the histogram. (Stop the app by closing the app window or using Ctrl+C).</p><p>The <code>runApp</code> function can take different types of arguments to run the same app. What you saw above was serving the app from a <strong>directory</strong> containing <code>app.R</code>. If you name the single file something else, e.g. <code>my-app.R</code>, you can provide the <strong>path to a single file</strong> as <code>runApp('~/your/path/my-app.R')</code>.</p><h3 id="multiple-files">Multiple files</h3><p>If your app is a bit more complex, you might have <strong>multiple files in the same directory</strong>. You can use the <code>runApp('~/your/path')</code> method to point to such a directory that contains <code>server.R</code> file and <code>ui.R</code> (or a <code>www</code> directory that contains the file <code>index.html</code>). You can save the parts of the simple app into three files.</p><p>The <code>global.R</code> file is used to load packages, data sets, set variables, or define functions that are available globally:</p><pre><code class="language-R"># global.R
library(shiny)</code></pre><p>The <code>server.R</code> file defines the <code>server</code> function which is called once for every R process:</p><pre><code class="language-R"># server.R
server &lt;- function(input, output) {
    output$distPlot &lt;- renderPlot({
        dist &lt;- rnorm(input$obs)
        hist(dist,
            col="purple",
            xlab="Random values")
    })
}</code></pre><p>The <code>ui.R</code> file defines the <code>ui</code> object:</p><pre><code class="language-R"># ui.R
ui &lt;- fluidPage(
    mainPanel(
        sliderInput("obs",
            "Number of observations",
            min = 1,
            max = 5000,
            value = 100),
        plotOutput("distPlot")
    )
)</code></pre><h3 id="programmatic-cases">Programmatic cases</h3><p>If you want to run the Shiny app as <strong>part of another function</strong>, you can supply a <strong>list</strong> with <code>ui</code> and <code>server</code> components (i.e. <code>shinyApp(list(ui = ui, server = server))</code>) or a Shiny <strong>app object</strong> created by the <code>shinyApp</code> function (i.e. <code>shinyApp(shinyApp(ui, server))</code>).</p><p>Note that when <code>shinyApp</code> is used at the R console, the Shiny app object is automatically passed to the <code>print()</code> function, which runs the app. If <code>shinyApp</code> is called in the middle of a function, the value will not be passed to <code>print()</code> and the app will not be run. That is why you have to run the app using <code>runApp()</code>:</p><pre><code class="language-R">run_app &lt;- function() {
  runApp(
    shinyApp(
      ui = fluidPage(
        mainPanel(
          sliderInput("obs",
            "Number of observations",
            min = 1,
            max = 5000,
            value = 100),
          plotOutput("distPlot")
        )
      ),
      server = function(input, output) {
        output$distPlot &lt;- renderPlot({
          dist &lt;- rnorm(input$obs)
          hist(dist,
            col="purple",
            xlab="Random values")
        })
      }
    )
  )
}</code></pre><p>Start the app by typing <code>run_app()</code> into the console.</p><h2 id="which-option-to-choose">Which option to choose</h2><p>The programmatic use case is best when the app is to be served from a function by a user running R interactively. Although it is possible to use such functions in non-interactive mode, for example as part of <a href="https://www.docker.com/">Docker</a> based deployments, it requires additional work.</p><p>The choice between singe vs. multiple files comes down to personal <strong>preference</strong> and the <strong>complexity</strong> of the shiny app. You might start with a single file, but as the file gets larger, you might decide to save the pieces into their own files. You might also add other files to the <code>www</code> folder etc.</p><p>Keeping Shiny apps <strong>in their own folder</strong> is generally a good idea irrespective of having single or multiple files in the folder. Changing your mind later won't affect how you run the app.</p><h2 id="further-reading">Further reading</h2><ul><li><a href="https://shiny.rstudio.com/articles/deployment-local.html">Sharing apps to run locally</a>: pros and cons of sharing apps via Gist, GitHub repository, zip file from URL, etc.</li><li><a href="https://shiny.rstudio.com/articles/function.html">Save your app as a function</a></li><li><a href="https://mastering-shiny.org/scaling-packaging.html">Include your app in an R package</a></li></ul>