Self-hosted deployment
DK Studio runs entirely on infrastructure you control: a Node process for the studio, one Node process per bench for the agents, and a database you choose. This page introduces the shape of an installation, the licence it runs under, the database and schema, the start order, and how to upgrade and restore.
This page covers the in-house installation β the mode in which the studio, the socket server and the database run on infrastructure you control. DK Studio also runs as a hosted studio, operated by DK Studio, where you install only the agents on your benches. The two modes are compared in Deployment modes.
The shape of a self-hosted install
| Application | Directory | Port | Runs where |
|---|---|---|---|
| DK Studio | apps/studio | 3000 | Your server. Serves the UI, the REST API and the Socket.IO endpoint from one process. |
| DK Studio Agent | apps/agent | 3001 | Every bench or machine that owns hardware. |
The studio never dials an agent. Each agent dials the studio over HTTP and Socket.IO, so a lab only needs outbound access β no inbound port, port forward or VPN client on the bench. See Network requirements.
The requirements are Node.js 24 or newer, pnpm 11, and a database. The agent additionally needs
bash at /bin/bash for the shell command, and the optional serialport native bindings if the
bench drives a serial port.
The studio's REST API answers anything that can reach port 3000. Keep the install on the lab network, or put an authenticating proxy in front of it. See Network requirements.
The studio licence
The studio's licence is a real entitlement, not a label. The file .studio-license.json records
edition, licenseKey, issuedAt, expiresAt, maxAgents and features, and the platform
enforces it: maxAgents bounds how many agents the install accepts, and features decides which
capability modules are available.
A licence key is written as xxxx-xxxx-xxxx-xxxx, and the first block names the edition.
| Edition | Key prefix | maxAgents | features |
|---|---|---|---|
| Starter | STR0 | 3 | core, agents |
| Professional | PRF0 | 10 | core, agents, analytics, api |
| Pro | PR00 | 25 | core, agents, analytics, api, advanced |
| Enterprise | ENT0 | 999 | core, agents, analytics, api, advanced, enterprise |
The demo key ENT0-DKST-UDIO-2026 is an enterprise licence with maxAgents 999, marked as a demo
licence. It passes validation as it stands, which makes it the key to use for a lab install.
.studio-license.json is created during the setup wizard and is the record of what the install is
entitled to run. Keep it with your backup, next to .db-config.json.
Agent licences are separate and narrower: each one is a single seat for one bench. See Agent registration and entitlements.
Database
The studio supports three engines, chosen during the setup wizard: SQLite (better-sqlite3),
PostgreSQL (pg) and MySQL (mysql2). The wizard writes the choice to .db-config.json in the
studio's working directory β {"dbType": "sqlite", "database": "dkstudio", "initializedAt": "β¦"},
plus host, port, username and password for the server-based engines. With SQLite the
database is a file under DATA_DIR, default ./data/dkstudio.db.
The engine is a storage choice only. On all three, the same studio process serves the UI, the REST API and the realtime socket, and the same schema backs them.
Schema
The schema comes from three parallel DDL files β apps/studio/lib/db/init.sqlite.sql,
init.postgresql.sql and init.mysql.sql β each defining 21 tables. They are applied once, by
the setup wizard's initialize step (POST /api/system/setup with {"step":"initialize"}).
SQLite executes the file as a whole; PostgreSQL and MySQL apply it statement by statement.
The 21 tables cover the platform end to end:
| Area | Tables |
|---|---|
| Identity and access | users, permissions, settings |
| Inventory | projects, products, environments, devices, vehicles, oems |
| Test domain | test_suites, test_cases, test_runs, executions, schedules, artifacts, reports |
| Agents | agents, agent_licenses, agent_commands, agent_keys, agent_sessions |
An upgraded studio does not re-apply the schema. Keep a copy of the DDL you deployed and apply schema changes by hand inside the maintenance window.
Start order
The order matters: the studio must be running before an agent can register.
- Start the studio
pnpm install pnpm build pnpm --filter @dkstudio/studio startFor development,
pnpm --filter @dkstudio/studio devruns the same server with hot reload. The studio listens on port 3000 by default and serves the UI, the REST API and the Socket.IO endpoint on that one port. - Complete the setup wizard
Open
http://<studio-host>:3000. The wizard validates the licence, configures the database, applies the 21-table schema and creates the admin account. Until an admin exists the studio keeps redirecting to the wizard. - Start the agents
On each bench:
pnpm install && pnpm --filter @dkstudio/agent build && pnpm --filter @dkstudio/agent start. The agent's own page opens on port 3001 and offers a registration form.For development,
pnpm --filter @dkstudio/agent devruns the same page with hot reload.
Both start scripts run TypeScript through tsx, which ships as a development dependency. Install
the workspace with a plain pnpm install β a production-only install leaves the server without
the runner it starts with.
Keeping the processes running
The studio is long-lived: it holds the Socket.IO connections and the database pool. The agent is long-lived on every bench. Run both under a supervisor so they come back after a crash or a reboot.
# /etc/systemd/system/dk-studio.service
[Unit]
Description=DK Studio
After=network.target
[Service]
Type=simple
User=dkstudio
WorkingDirectory=/opt/dk-studio/apps/studio
Environment=NODE_ENV=production
Environment=PORT=3000
Environment=DATA_DIR=/var/lib/dk-studio
ExecStart=/usr/bin/pnpm --filter @dkstudio/studio start
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetThe working directory is where the four studio files live, so it decides where .db-config.json,
.studio-license.json and .setup-complete are found. DATA_DIR moves only the SQLite database
file; the other three stay in the working directory.
The agent takes the same shape on the bench, with AGENT_HOST left at its default so the bench
page stays on the machine:
# /etc/systemd/system/dk-studio-agent.service
[Unit]
Description=DK Studio Agent
After=network.target
[Service]
Type=simple
User=dkstudio
WorkingDirectory=/opt/dk-studio/apps/agent
Environment=NODE_ENV=production
ExecStart=/usr/bin/pnpm --filter @dkstudio/agent start
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetThe agent registers once, through its own page, and then reconnects on its own after a restart β
data/agent.json holds the credentials it needs.
systemctl enable --now dk-studio
systemctl enable --now dk-studio-agentThe studio keeps four files in its working directory: .db-config.json (driver and connection
details), .studio-license.json (edition, maxAgents, features), .setup-progress.json (setup
progress, safe to delete once complete) and .setup-complete (the marker that gates the wizard).
Upgrading
git pull
pnpm install
pnpm buildStop the studio process, take a backup (below), then start it again with
pnpm --filter @dkstudio/studio start. The wizard does not reappear: .setup-complete and
.db-config.json are still in place.
The socket envelope is {v, type, kind, id, timestamp, payload} and the protocol version is
negotiated during the handshake. Update the studio and every agent in the same maintenance
window so that both ends speak the same version.
Backup and restore
What to back up, for a SQLite deployment (with the studio stopped):
cp data/dkstudio.db /backup/dkstudio-$(date +%F).db
cp .db-config.json .studio-license.json .setup-complete /backup/For PostgreSQL and MySQL, use the engine's own dump tooling (pg_dump, mysqldump) and back up
.db-config.json alongside it. The database is the source of truth; the JSON files only tell the
studio how to reach it and what it is entitled to run.
Restore in this order: stop the studio; put the database back; put .db-config.json back in the
studio's working directory β without it the studio presents the setup wizard again and starts with
an empty view of the world; then start the studio and confirm the agent list is populated.
The agent's own state lives on the bench in data/agent.json, in plain text. It is not part of the
studio's backup set β but the studio's agents table holds the same api_key and agent_secret
values, so a database backup carries the same secret material.
Related pages
- Network requirements β who dials whom, and which ports.
- Agent registration and entitlements β issuing licences.
- Device topology and physical connection β wiring the benches.
- Configuration β every environment variable and file.
- Setup wizard β the first-run flow.