Viewer guide

Run without Docker

A systemd unit that runs the Viewer from a checkout, the four settings that unit gets wrong by default, and how to update it later.

Docker is the shortest path; see Deploy the Viewer. This page is for a Linux host where you would rather run the process directly.

There is no bundled process manager and no published package: the Viewer runs from a monorepo checkout. A systemd unit is the shortest path on a Linux host.

You need Node 24 or newer and git on the host. The Viewer needs git of its own too: it clones each repository it builds.

Clone the repository once, at /opt/desde:

git clone https://github.com/desde-design/desde.git /opt/desde

Then, from /opt/desde:

npm install
npm install --prefix viewer
npm run build --prefix viewer

There is no bridge to build. The script the Viewer adds to every prototype it serves is committed, and kept current with its source on every commit.

The last command is next build. It is required: the start script sets NODE_ENV=production, which makes the process serve the prebuilt .next directory instead of compiling on demand. Skip it and routes go missing with no error.

Note that start does not read viewer/.env.local; only the :local scripts do. So systemd supplies the environment:

[Unit]
Description=Desde Viewer
After=network-online.target
Wants=network-online.target
 
[Service]
Type=simple
User=desde
WorkingDirectory=/opt/desde
EnvironmentFile=/etc/desde/viewer.env
ExecStart=/usr/bin/npm run start --prefix viewer
Restart=on-failure
RestartSec=5
 
[Install]
WantedBy=multi-user.target

Put that at /etc/systemd/system/desde-viewer.service, then:

sudo systemctl enable --now desde-viewer

A few notes on that unit:

  • Set VIEWER_DATA_DIR to an absolute path in the environment file. Its default, .desde-viewer, is relative and resolves against the working directory. Start the process from two different directories and you get two different databases with no warning.
  • Confirm the npm path with which npm: it is not /usr/bin/npm on every distribution or under a version manager.
  • EnvironmentFile has the same one-line-values constraint as Docker's --env-file, so use the base64 form of the App private key here too.
  • The process handles SIGTERM and shuts down cleanly: it marks any in-flight build failed (otherwise it stays building forever in the UI) and closes the database. Do not configure KillMode=process or a short TimeoutStopSec.

Updating#

Updating a checkout is a pull, the same install and build commands, and a restart. Take a backup first, for the reason on Upgrading: the database is migrated forward at startup and there is no way back except the backup.

From /opt/desde:

git pull
npm install && npm install --prefix viewer
npm run build --prefix viewer
sudo systemctl restart desde-viewer

Do not skip the build. next build is what the production start script serves, so an old build means old screens with no error to tell you so. The pull brings the new bridge script with it, and the restart loads it.

systemctl restart stops the process cleanly, so a build running at that moment is recorded as failed rather than left half done. Run it again afterwards.

Upgrading covers the rest, and all of it applies here: keeping the data directory and any VIEWER_SESSION_SECRET you set unchanged so nobody is signed out, and why rolling back means restoring the backup rather than checking out an older commit.