Add and edit apps
The Library page holds every entry Polaris publishes to clients: the Desktop entry, Steam Big Picture, and the games and launchers you add. This guide covers the page itself and every field in the app editor. Artwork sources and fixes are on Library sources and artwork.
The Library page
Section titled “The Library page”Quick Launch ranks favourite, recent, and launch-ready apps first so the list feels familiar from the couch, while still surfacing entries that need attention.
Published apps is the list clients see. Drag rows to reorder what appears first. Reordering,
like any change to the published list, makes Polaris rebuild it, which can interrupt a running
session. Open an entry to edit it or to export its .art launcher file for front ends that want a
direct launch.
Find covers looks up every published game that has no cover, in one pass, and proposes a match for each. It proposes and stores nothing: Review proposals lists what it found, one row per game, with the title the provider matched and how close that is to the entry’s own name. Open a row to see that game’s posters and pick a different one. Untick anything that looks wrong, then Apply stores only what is left ticked.
A title search is right most of the time rather than always, which is why the review exists: three hundred imported ROMs would otherwise become three hundred guesses to undo by hand. Games Polaris ships artwork for are never looked up, because a search for one of those finds a coincidental game rather than nothing, and a game you used Remove artwork on is left alone until you use Find artwork again. The run needs the SteamGridDB API key from Settings, General, and says so when the key is missing. It paces itself and waits out a provider that asks it to slow down, so a large library takes a few minutes.
Import games scans Steam, Lutris, Heroic and the ROM folders you register for installed titles, keeps entries that are already published visible so you can spot what is new, and lets you stage several candidates before one import pass. Imported Steam titles keep their app id and take the Linux launch mode you have selected when they start.
Before importing, you can enable Automatically add matching covers. It is off by default. With a SteamGridDB key, Polaris then looks up only the games that import actually added and applies the first suggested match and poster to entries with an empty cover path. Large imports continue in batches of 500. Keep the Library page open until it finishes; Stop prevents further automatic applications, although a save already in progress may finish. Search matches can need correction; use the app editor’s Find Cover to choose another.
Existing covers, Artwork Studio selections and Remove artwork choices are preserved. An entry renamed or removed during its lookup is skipped, and other edits survive. Cover-only saves refresh the library without ending a running game. A missing key or failed lookup leaves the imported games available for the normal Find covers review.
Importing a Lutris or Heroic title also publishes an entry for the launcher itself, once, using the command that exists on this host. Those imports launch straight into a game, so without it there is no way to reach the launcher from a stream to install something or fix a login. An entry you added by hand is recognised and not duplicated.
ROM folders
Section titled “ROM folders”Emulator games come in the same way; Emulators and ROM folders walks the whole
path, from keys and BIOS files to what happens on End Session. In the import console, add a folder and pick the emulator
that loads it. Polaris lists every file with a matching extension as a candidate, named from its
filename with the region and version tags removed and Legend of Zelda, The read as The Legend of Zelda, and skips update and DLC dumps ([v65536], [UPD], (DLC), or a folder called
updates or dlc). A second dump of the same game, another region say, does not become a second
entry. The folder is remembered, so Rescan Sources finds games you add later.
An imported entry launches the emulator straight into the game, fullscreen where the emulator has
a switch for it, with the Emulated Gamepad Type set for the platform: a Switch Pro pad for
Eden, a DualSense for the PlayStation emulators. A cover that already sits next to the game
(<name>.png, or in a covers, boxart or media folder beside it), in ES-DE’s downloaded
media for that system, or among RetroArch’s boxarts for it, is copied in at import, so the entry
has art without any key; otherwise covers come from SteamGridDB when an API key is set in Settings,
like any entry without artwork of its own. The emulator itself is published once
next to its games so its own UI stays reachable from a stream.
Polaris looks for each emulator in this order: the emulator file you set on the folder (an
AppImage, say), a binary on the service’s PATH, then the Flatpak. A folder whose emulator is not
installed still imports; the entries launch once it is. The folder card also names what the
emulator still lacks before a game boots, with the fix: Eden’s prod.keys, Cemu’s keys.txt, a
BIOS image for DuckStation or PCSX2, or a Flatpak that has not been allowed to read the folder.
Library health counts the folders that are ready.
| Emulator | Files | Command Polaris writes |
|---|---|---|
| Eden (Nintendo Switch) | nsp, xci, nca, nro, nso | eden -f -g '<rom>' |
| Dolphin (GameCube and Wii) | iso, gcm, wbfs, rvz, ciso, gcz, wia, wad, dol, elf | dolphin-emu -b -e '<rom>' |
| Cemu (Wii U) | wua, wud, wux, rpx | Cemu -f -g '<rom>' |
| DuckStation (PlayStation) | cue, chd, iso, pbp, m3u, img, ecm, mds | duckstation-qt -batch -fullscreen '<rom>' |
| PCSX2 (PlayStation 2) | iso, chd, cso, zso, gz, bin, elf | pcsx2-qt -batch -fullscreen '<rom>' |
| PPSSPP (PlayStation Portable) | iso, cso, chd, pbp | PPSSPPSDL '<rom>', fullscreen follows PPSSPP’s own setting |
| mGBA (Game Boy Advance) | gba, gb, gbc, sgb | mgba-qt -f '<rom>' |
A Flatpak runs as flatpak run <app id> with the same arguments, and it has to be allowed to read
the folder: Flatseal, or flatpak override --user --filesystem=<folder> <app id>. For any other
emulator choose Custom command, give the command with {rom} where the file goes, for example
retroarch -f -L ~/.config/retroarch/cores/snes9x_libretro.so {rom}, and the extensions to look
for. The file path is single-quoted when it is substituted, and ~/ at the start of an argument is
expanded; the command runs without a shell, so nothing else is.
Library health shows import coverage and the host context the library depends on. Keep
entries short and recognisable on a handheld screen, use per-app overrides only where a launcher,
tool, or game needs them, and export .art entries when you want favourite launches in another
front end.
The app editor
Section titled “The app editor”Saving writes the launcher profile immediately; there is no separate apply step.
Client entry
Section titled “Client entry”| Field | What it does |
|---|---|
| Application Name | The name shown on Moonlight and Nova. |
| Image | The icon, picture, or box image sent to clients: PNG, JPEG or WebP. A bare file name such as lutris.png or heroic.png names an image Polaris ships. When unset, Polaris sends its default box image. Find Cover searches SteamGridDB through the host for the name you type and shows up to five of the games it matches that have a poster, with their titles and years. It reads past matches without one, so “Heroic” finds Heroic Games Launcher. Picking a game shows up to five of its posters, the ones Nova’s Artwork Studio offers for it, and All Matches goes back. Picking a poster saves the full image in Polaris’s covers directory and puts its path here; the entry uses it once you save. The search needs the SteamGridDB API key from Settings, General, and says so, with a link to that field, when the key is missing. |
| Artwork in Nova | How Nova gets posters, backgrounds, logos and icons for a saved entry, with Remove artwork and Find artwork again. See Artwork in Nova. |
| Game Category | A classification hint for Auto Quality, detected from Steam genres on import. |
| Platform and runtime | Filled in for titles imported from Heroic. Says what the title installs as and what will execute it, such as Windows through Proton-GE. Left blank when Heroic did not record it. |
| Emulated Gamepad Type | Which gamepad to emulate for this app, overriding the Input tab’s default. |
| MangoHud Overlay | Shows GPU, CPU, temperature, and frametime in the stream from the host side. |
Artwork in Nova
Section titled “Artwork in Nova”An entry’s image is its poster in Nova. A new image, including a second cover picked into the same file, replaces the poster the next time Nova loads the library, and clearing the image lets the next source show.
Artwork picked in Nova comes before the entry’s image. A cover you pick with Find Cover takes the poster back: saving the entry then drops the poster picked in Nova and keeps its background, logo and icon. Any other image leaves Nova’s pick alone, whether you typed the path yourself or a library rescan refreshed the cover an import downloaded.
When Nova shows an entry without artwork of its own, Polaris looks it up. A Steam title gets Steam’s images, and with a SteamGridDB key set in Settings the rest comes from its SteamGridDB game, found by app id. Any other entry gets SteamGridDB artwork only when a search finds a game with exactly the entry’s name, ignoring case, punctuation and trademark signs. A similar name is never used, so an entry SteamGridDB does not know keeps its own image. Desktop, Low Res Desktop and any other entry that streams the desktop never look anything up, and artwork an earlier version downloaded for them is removed.
Remove artwork deletes every picture Polaris downloaded for a saved entry, and any you picked in Nova, and stops Polaris looking up new ones. The entry’s own image stays, and Nova shows it the next time its library loads. Find artwork again turns the lookup back on; it does not bring the deleted pictures back. Picking artwork in Nova still works after a removal.
Command path
Section titled “Command path”| Field | What it does |
|---|---|
| Command | The main application to start. Leave it blank to publish an entry that starts nothing, such as the Desktop. |
| Working Directory | Passed to the process; some applications look for their configuration there. Defaults to the parent directory of the command. |
| Output | A file that receives the command’s output. Ignored when unset. |
| Detached Commands | Commands run in the background alongside the app. |
Prep and state commands
Section titled “Prep and state commands”| Field | What it does |
|---|---|
| Command Preparations | Commands run before the app starts and undone after the session ends. If any preparation fails, the launch is aborted. |
| Resume/Pause Commands | The do command runs when the first client connects to an idle app; the undo command runs when the last client disconnects. Clean up in undo what do sets up. |
| Global prep and state commands | Per-app switches that include or exclude the host-wide commands from the General tab for this app. |
| Allow client prepare commands | Whether the commands a paired device carries may run when this app starts. |
Runtime behavior
Section titled “Runtime behavior”| Field | What it does |
|---|---|
| Exit Timeout | Seconds to wait for every app process to exit gracefully when quitting; five by default. Zero or below terminates immediately. In a private-compositor session the wait is at least two seconds and at most thirty, so an emulator can finish writing its save. |
| Resolution Scale Factor | Scales the client-requested resolution: 2000x1000 at 120 percent becomes 2400x1200. Only a value other than 100 percent overrides the client’s own factor; the stream mode itself is not affected. |
| Continue streaming until all app processes exit | Keeps streaming until every process the app started has ended, instead of stopping when the first one does. |
| Continue streaming if the application exits quickly | Detects launcher-type apps that close right after starting something else and treats them as detached. |
| Terminate on Pause | Ends the app when the last client disconnects instead of keeping it paused for the resume window. |
| Mirror the host desktop | Linux only. Streams the desktop you see on the host whatever launch mode the host uses, and ignores Always create Virtual Display for this entry. The bundled Desktop entry has it on, which is why Desktop shows your real desktop on a Private Stream host. Turn it off, or add an entry with no command, to get an empty private session to launch things into. A Desktop Takeover launch ignores it. |
| Close desktop Steam for private launches | When desktop Steam is running as a private stream starts, quits it and waits for it to exit instead of refusing the launch. Unsaved state in that Steam session is lost. |
| Per Client App Identity | Gives the app a separate identity per client, so one app can carry different virtual display configurations for different devices. |
| Use App Identity | Creates virtual displays under the app’s own identity instead of the client’s, so each app gets its own display configuration. |
| Always create Virtual Display | Creates a virtual display whenever this app starts, regardless of what the client asked for. Needs the virtual display driver on Windows hosts. |
| Enforce Virtual Display Primary | Makes the virtual display primary when the app starts. Kept on by default; known broken on Windows 11 24H2. |
Environment variables
Section titled “Environment variables”Every command the app runs receives a set of environment variables describing the session:
client, resolution, frame rate, and the like. The editor lists them under the Reference section.
Variables starting with SUNSHINE_ are kept for compatibility with tools written for that host;
their POLARIS_ twins are the current names. SUNSHINE_CLIENT_FPS carries a fractional value for
fractional refresh rates; if a script cannot read a floating-point number there, enable ENVVAR
compatibility mode on the Advanced tab. POLARIS_CLIENT_FPS is always fractional.