---
title: "Configuration Guide"
vignette: >
%\VignetteIndexEntry{Configuration Guide}
%\VignetteEngine{quarto::html}
%\VignetteEncoding{UTF-8}
knitr:
opts_chunk:
collapse: true
comment: "#>"
---
```{r}
#| include: false
library(shinyelectron)
```
A `_shinyelectron.yml` file keeps your build settings next to your app. `export()` reads it automatically, so the function call stays short and the details live in version control where the rest of the project already does.
Every `_shinyelectron.yml` section at a glance: nine knobs that shape a different part of the build, from app metadata and target platforms down to the runtime and the optional multi-app launcher.
## Why use one
Compare a fully specified call:
```{r}
#| eval: false
export(
appdir = "my-app",
destdir = "output",
app_name = "My Application",
app_type = "r-shiny",
runtime_strategy = "shinylive",
platform = c("mac", "win"),
arch = c("x64", "arm64"),
icon = "icons/icon.png"
)
```
With the same build driven by config:
```{r}
#| eval: false
export(appdir = "my-app", destdir = "output")
```
A config file pulls double duty. It is a set of arguments to `export()`, but it is also a short document telling anyone who clones the repo how the app is meant to be built.
## Getting a config file in place
The config file must be named `_shinyelectron.yml` and live at the root of your app directory:
```
my-shiny-app/
├── _shinyelectron.yml # Configuration file
├── app.R # Your Shiny app
└── ...
```
Generate a starter template with `init_config()`:
```{r}
#| eval: false
init_config("path/to/my-app")
```
```
✔ Created configuration file: path/to/my-app/_shinyelectron.yml
ℹ Edit this file to customize your Electron app settings
```
The generated file carries the documented defaults you can edit in place. For most projects, the only setting you need to write yourself is the app name:
```yaml
app:
name: "My App"
```
Everything else is filled in by defaults described below.
## Complete reference
Every available option, annotated. Each section is covered in more detail further down.
```yaml
# shinyelectron configuration file
# Documentation: https://r-pkg.thecoatlessprofessor.com/shinyelectron/
app:
name: "My Application" # Application display name
version: "1.0.0" # Application version (used in package metadata)
build:
type: "r-shiny" # Application language (autodetected if omitted)
runtime_strategy: "shinylive" # shinylive, auto-download, bundled, system, container
platforms: # Target platforms
- mac
- win
- linux
architectures: # Target architectures
- x64
- arm64
dependencies: # Runtime version pins and system packages
r:
version: null # null = maintained pin; "latest" = live query; "4.6.1" = exact
python:
version: null # null = maintained pin; "latest" = live query; "3.12.0" = exact
electron:
version: null # null = maintained pin; "latest" = live query from npm; "41.0.0" = exact
# system_packages: extra apt packages baked into the container image
# system_packages:
# - libgdal-dev
# - libpq-dev
window:
width: 1200 # Default window width (pixels)
height: 800 # Default window height (pixels)
server:
port: 3838 # Development server port
icon: "branding/icon.png" # Single high-res source; electron-builder fans out to each platform
# Optional per-platform icon overrides (rarely needed):
# icons:
# mac: "branding/icon.icns"
# win: "branding/icon.ico"
# linux: "branding/icon.png"
nodejs:
version: null # Node.js version (null = latest LTS)
# auto_install: false # Planned: auto-install Node.js if not found (not yet implemented)
container: # Used when runtime_strategy is "container"
engine: "docker" # "docker" or "podman"
image: null # Container image (null = use bundled Dockerfile)
tag: null # null = resolved runtime version; "latest" for BYO image
pull_on_start: true # Pull latest image on app start
volumes: # Host-to-container volume map (not a list)
"/data": "/app/data"
env: # Environment variable map (not a list)
SHINY_LOG_LEVEL: "debug"
# Multi-app suite (2+ apps packaged in one Electron shell)
# apps:
# - id: "dashboard"
# name: "Dashboard"
# path: "./apps/dashboard"
# type: "r-shiny" # Optional per-app override (default: build.type)
# runtime_strategy: "shinylive" # Optional per-app override (default: build.runtime_strategy)
# description: "Main dashboard"
# icon: "icons/dash.png"
# - id: "admin"
# name: "Admin Panel"
# path: "./apps/admin"
```
::: {.callout-note}
## How values get resolved
When `export()` runs, it merges three sources in priority order:
1. **Function arguments** passed directly to `export()`
2. **Config file** values from `_shinyelectron.yml`
3. **Built-in defaults**
A function argument always wins. So `export(appdir = "app", destdir = "out", app_name = "Override")` uses `"Override"` even if the config file says something else, and everything else falls through to the config or the defaults.
:::
## Section reference
### `app`
Application metadata.
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `name` | string | Directory name | Display name shown in window title and system |
| `version` | string | `"1.0.0"` | Version number for the built application |
### `build`
The build process and its targets.
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `type` | string | autodetect | Application language (see below). Autodetected from files in `appdir` if omitted. |
| `runtime_strategy` | string | `"shinylive"` | How the app's runtime reaches the user (see below) |
| `platforms` | list | Current platform | Target operating systems: `mac`, `win`, `linux` |
| `architectures` | list | Current arch | Target CPU architectures: `x64`, `arm64` |
**Valid `type` values:** `r-shiny` (an `app.R` or `ui.R`/`server.R` Shiny app) or `py-shiny` (an `app.py` Shiny for Python app).
**Valid `runtime_strategy` values:**
| Strategy | Description |
|----------|-------------|
| `shinylive` | Compiles to WebAssembly and runs in-browser via WebR or Pyodide (default) |
| `auto-download` | Downloads R or Python on first launch, caches for reuse |
| `bundled` | Embeds a portable R or Python runtime inside the app at build time |
| `system` | Uses R or Python already installed on the end user's machine |
| `container` | Runs the app inside a Docker or Podman container |
All five strategies work with both `r-shiny` and `py-shiny`. See the [Runtime Strategies](runtime-strategies.html) vignette for the full discussion.
::: {.callout-note}
## Cross-platform caveats
macOS apps build only on macOS. The `bundled` strategy ships a platform-specific runtime binary, so exporting for Windows from macOS is not supported for bundled builds. `auto-download`, `system`, and `container` sidestep that constraint. See the Runtime Strategies vignette for the full story.
:::
### `icon` and `icons`
A single top-level `icon` entry is the simplest and recommended shape. Point it at a high-resolution PNG (1024×1024 or larger) and electron-builder will generate the per-platform variants it needs (`.icns` for macOS, `.ico` for Windows, and the PNG itself for Linux).
```yaml
icon: "branding/icon.png"
```
If you genuinely need different artwork on different platforms (for example, a monochrome Windows icon alongside a full-color macOS icon), use the per-platform `icons` map as an override:
| Key | Type | Format | Description |
|-----|------|--------|-------------|
| `mac` | string | `.icns` | macOS icon (typically 512×512 or larger) |
| `win` | string | `.ico` | Windows icon (multi-resolution recommended) |
| `linux` | string | `.png` | Linux icon (512×512 recommended) |
Paths are relative to the app directory. When no icon is set at all, the build uses the default Electron icon.
::: {.callout-tip}
## Creating icons
Start from one 1024×1024 PNG. That single file is enough for the default `icon:` path; electron-builder handles the conversions. If you need hand-tuned `.icns` or `.ico` artwork, convert with
[iconutil](https://developer.apple.com/library/archive/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html)
on macOS, [ImageMagick](https://imagemagick.org/), or any online converter.
:::
### `window`
Electron window dimensions.
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `width` | integer | `1200` | Window width in pixels (minimum 100) |
| `height` | integer | `800` | Window height in pixels (minimum 100) |
### `server`
Development server settings.
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `port` | integer | `3838` | Port for the local Shiny server (1 to 65535) |
### `nodejs`
Node.js installation behavior.
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `version` | string | `null` | Node.js version to install (`null` = latest LTS) |
::: {.callout-note}
## `auto_install` is planned, not yet active
An `auto_install` key is reserved for a future release. Today, a missing Node.js aborts the build with guidance to run `install_nodejs()` or install Node.js manually. Do not rely on `auto_install: true` having any effect.
:::
### `dependencies`
Controls runtime version pins and (for the container strategy) system-level apt packages.
#### Version keys
Each runtime has a `version` key under its own sub-section. Three values are accepted:
| Value | Effect |
|-------|--------|
| `null` or omitted | Uses the maintained latest pin shipped with shinyelectron |
| `"latest"` | Queries the upstream source at build time for the newest available version |
| A version string such as `"4.6.1"` | Uses that exact version for the build |
The maintained pins are updated with each shinyelectron release. Using `null` is recommended for most projects: you get a version known to work, and you can pin explicitly when you need a specific release.
A custom version must correspond to a build the upstream source actually publishes. The maintained pin resolves offline; other versions are resolved against the upstream releases at build time (portable-r for R, python-build-standalone for Python), so a very old patch version may no longer be available. If a pin cannot be resolved, the build aborts with a message pointing you back to the maintained default.
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `r.version` | string | `null` | R version for `bundled`, `auto-download`, and `container` strategies |
| `python.version` | string | `null` | Python version for `bundled`, `auto-download`, and `container` strategies |
| `electron.version` | string | `null` | Electron (Chromium/Node) runtime version bundled in the desktop app; written as `^` in `package.json` |
The support toolchain (`electron-builder`, `electron-updater`, `electron-log`) is pinned internally by shinyelectron and is not user-configurable via `_shinyelectron.yml`. Node.js is the build toolchain taken from the system PATH and is not bundled in the app; it is managed via the `nodejs` section below.
`r.version` and `python.version` apply only to the `bundled`, `auto-download`, and `container` strategies. They have no effect under `shinylive`, where the R or Python runtime is the WebR or Pyodide version shipped by the `shinylive` package (set upstream, not configurable here), or under `system`, where the app runs against the end user's installed R or Python.
#### Detection and extra packages
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `auto_detect` | boolean | `true` | Automatically scan the app source to detect required R or Python packages (applies to `bundled`, `auto-download`, and `container` strategies) |
| `extra_packages` | list of strings | `[]` | Additional packages to include beyond those auto-detected |
#### R-specific dependency options
These keys sit under `dependencies.r` and apply to the `bundled`, `auto-download`, and `system` strategies.
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `r.packages` | list of strings | `[]` | R packages to install alongside the app |
| `r.repos` | list of strings | `["https://cloud.r-project.org"]` | CRAN-compatible repository URLs to use when installing R packages |
| `r.lib_path` | string | `null` | Custom library path where R packages are installed; `null` uses the default R library |
#### Python-specific dependency options
These keys sit under `dependencies.python` and apply to the `bundled`, `auto-download`, and `system` strategies.
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `python.packages` | list of strings | `[]` | Python packages to install alongside the app |
| `python.index_urls` | list of strings | `["https://pypi.org/simple"]` | Package index URLs used when installing Python packages |
#### `system_packages`
A list of apt package names baked into the container image at build time. Used only when `runtime_strategy` is `"container"`.
For R apps, shinyelectron already queries the Posit Package Manager system-requirements service to auto-detect system libraries required by your R packages (for example, `libgdal-dev` for `sf`) and bakes them in automatically. `system_packages` is the escape hatch for anything not covered by that auto-detection.
For Python apps, auto-detection is not performed. `system_packages` is the only way to add system-level libraries to the image.
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `system_packages` | list of strings | `null` | Extra apt packages baked into the container image (container strategy only) |
**Example:**
```yaml
dependencies:
r:
version: "4.6.1" # pin to an exact R release
python:
version: null # use maintained pin
electron:
version: "latest" # resolve newest Electron from npm at build time
system_packages:
- libgdal-dev
- libpq-dev
```
`system_packages` has no effect for `shinylive`, `bundled`, `auto-download`, or `system` strategies.
### `container`
Used when `runtime_strategy` is `"container"`. Ignored otherwise.
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `engine` | string | `"docker"` | Container engine: `"docker"` or `"podman"` |
| `image` | string | `null` | Container image name (`null` = auto-select based on `app.type`) |
| `tag` | string | `null` | Image tag. For the bundled Dockerfile (`image: null`), defaults to the resolved runtime version (e.g. `"4.6.1"` for R). For a BYO `image`, defaults to `"latest"`. |
| `pull_on_start` | boolean | `true` | Pull the latest image when the app starts |
| `volumes` | map | `{}` | Host-to-container volume mounts (`host: container`) |
| `env` | map | `{}` | Environment variables (`KEY: value`) |
**Example:**
```yaml
container:
engine: "docker"
image: "rocker/shiny"
tag: "4.4.1"
pull_on_start: true
volumes:
"/data": "/app/data"
env:
SHINY_LOG_LEVEL: "DEBUG"
```
### `apps`
Defines a multi-app suite: two or more Shiny apps packaged in one Electron shell with a launcher screen. At least two entries are required. Any entry can override `build.type` or `build.runtime_strategy`, which is how mixed-strategy suites work. One constraint applies: within a language, all native apps (`system`, `bundled`, `auto-download`) must share one strategy; `shinylive` and `container` apps combine freely. Export aborts on a conflict. See the [Multi-App Suites](multi-app-suites.html) vignette for details.
| Key | Type | Required | Description |
|-----|------|----------|-------------|
| `id` | string | yes | Unique identifier (URL-safe) |
| `name` | string | yes | Display name in the launcher |
| `path` | string | yes | Relative path to the app directory |
| `type` | string | no | App type override (default: `build.type`) |
| `runtime_strategy` | string | no | Runtime strategy override (default: `build.runtime_strategy`) |
| `description` | string | no | Short description shown in the launcher |
| `icon` | string | no | Per-app icon path |
**Example:**
```yaml
apps:
- id: "dashboard"
name: "Dashboard"
path: "./apps/dashboard"
description: "Sales analytics dashboard"
- id: "admin"
name: "Admin Panel"
path: "./apps/admin"
type: "py-shiny"
description: "User management"
```
See the [Multi-App Suites](multi-app-suites.html) vignette for mixed-strategy examples and launcher customization.
### `logging`
Controls where and how the app writes its log files.
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `log_dir` | string | `null` | Directory for log files; `null` writes to the Electron app's `userData/logs` directory |
| `log_level` | string | `"info"` | Logging verbosity: `"debug"`, `"info"`, `"warn"`, or `"error"` |
**Example:**
```yaml
logging:
log_dir: "/var/log/my-app"
log_level: "debug"
```
### `lifecycle`
Controls the lifecycle window that fills the gap between launch and app readiness. See the [Customizations](customizations.html) guide for the visual options (splash image, preloader style, etc.). The keys below govern behavior and timeout rather than appearance.
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `show_phase_details` | boolean | `true` | Show the phase-detail line under the preloader headline |
| `error_show_logs` | boolean | `true` | Show the collapsible error-log block in the error state |
| `shutdown_timeout` | integer (ms) | `10000` | Maximum milliseconds to wait for backend teardown before force-quitting |
| `custom_splash_html` | string | `null` | Raw HTML replacing the entire splash state; `null` uses the built-in splash |
| `custom_error_html` | string | `null` | Raw HTML replacing the entire error state; `null` uses the built-in error view |
| `prompt_before_install` | boolean | `false` | Prompt the user before installing missing R or Python packages |
| `prompt_runtime_version` | boolean | `false` | Show a runtime-version picker when multiple R or Python installations are detected |
### `installer`
Controls installer branding and behavior for the Windows (NSIS) installer produced by electron-builder.
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `app_id` | string | `null` | Unique application identifier (e.g. `"com.example.myapp"`); `null` derives one from the app name |
| `license_file` | string | `null` | Path to a license file shown during installation (Windows NSIS only) |
| `one_click` | boolean | `true` | Use a one-click installer on Windows; set to `false` for a wizard-style installer |
**Example:**
```yaml
installer:
app_id: "com.example.my-dashboard"
license_file: "LICENSE.txt"
one_click: false
```
## Common recipes
### Development setup
Fast iteration while you work:
```yaml
app:
name: "My App (Dev)"
version: "0.0.1"
window:
width: 1000
height: 700
```
### Production multi-platform build
For distribution across platforms:
```yaml
app:
name: "Production App"
version: "1.0.0"
build:
type: "r-shiny"
runtime_strategy: "shinylive"
platforms:
- mac
- win
- linux
architectures:
- x64
- arm64
window:
width: 1200
height: 800
icon: "branding/icon.png"
nodejs:
version: "22.11.0"
```
### Native R app with bundled runtime
Ship R inside the app:
```yaml
app:
name: "Analytics Tool"
version: "1.0.0"
build:
type: "r-shiny"
runtime_strategy: "bundled"
platforms:
- mac
- win
dependencies:
r:
version: "4.4.1"
```
### Multi-app suite
Several apps behind one launcher:
```yaml
app:
name: "My App Suite"
version: "1.0.0"
build:
type: "r-shiny"
runtime_strategy: "auto-download"
apps:
- id: "dashboard"
name: "Dashboard"
path: "./apps/dashboard"
description: "Sales analytics"
- id: "admin"
name: "Admin Panel"
path: "./apps/admin"
type: "py-shiny"
description: "User management"
```
## What happens when a value is invalid
shinyelectron validates values on read and degrades gracefully rather than aborting the build:
- Invalid `type` values warn and fall back to autodetect.
- Invalid `runtime_strategy` values warn and fall back to `shinylive`.
- Invalid platforms and architectures are dropped with a warning.
- Window dimensions under 100 pixels warn and use defaults.
- Invalid port numbers warn and use `3838`.
If the YAML itself fails to parse, shinyelectron warns and uses all defaults. This is deliberate: a broken config file should never block you from producing a build during development.
## Next steps
- **[Getting Started](getting-started.html)**: first-time user walkthrough.
- **[Runtime Strategies](runtime-strategies.html)**: deep dive on `build.runtime_strategy`.
- **[Node.js Management](nodejs-management.html)**: managing a local Node.js install.
- **[Troubleshooting](troubleshooting.html)**: diagnosing build issues.