Installation
Studio requires an existing ExpressoTS v4 application. If you don't have one yet, scaffold it with the CLI:
expressots new my-app
Step 1: Install the packages
Studio ships as two packages. Install both as dev dependencies:
- npm
- yarn
- pnpm
npm install -D @expressots/studio @expressots/studio-agent
yarn add -D @expressots/studio @expressots/studio-agent
pnpm add -D @expressots/studio @expressots/studio-agent
| Package | Why |
|---|---|
@expressots/studio | The CLI, orchestrator, and bundled web UI you run on your laptop |
@expressots/studio-agent | Loaded into your app process. It instruments routes, records, and scans |
The agent is a peer dependency of @expressots/adapter-express. The adapter auto-detects it at startup; no app.ts changes are required.
Step 2: Run your app
Start your app the way you normally do:
npm run dev
When the app boots in development mode, the adapter dynamically imports @expressots/studio-agent and you should see:
[ExpressoTS] Studio Agent listening on ws://localhost:3334
If you don't see that line, jump to Troubleshooting.
Step 3: Launch the Studio UI
In a second terminal:
npx expressots-studio
The UI opens automatically at http://localhost:3333. It connects to the agent over Socket.IO and immediately starts showing recorded traffic, logs, and the architecture map.
Activation rules
The studio-agent only loads when all of the following are true:
@expressots/studio-agentis installed innode_modules.NODE_ENV === "development"orNODE_ENVis not set.EXPRESSOTS_STUDIOis not equal to"false".
Production deployments (NODE_ENV=production) never import the agent module, so there is zero runtime overhead in production.
To force-enable Studio in a non-dev NODE_ENV (e.g. a staging probe), call this.setStudio({ enabled: true }) on your App class:
import { AppExpress } from "@expressots/adapter-express";
export class App extends AppExpress {
protected globalConfiguration(): void {
this.setStudio({
enabled: true,
port: 3334,
dbPath: ".studio/studio.db",
});
}
}
setStudio() accepts enabled, port, dbPath, and serviceName. Call it before the server starts listening (e.g. in globalConfiguration()) so the agent picks the config up during initialization.
Environment variables
| Variable | Default | Description |
|---|---|---|
EXPRESSOTS_STUDIO | (unset) | Set to false to force-disable the agent even in development. |
EXPRESSOTS_STUDIO_PORT | 3334 | WebSocket port the agent listens on. Must match the UI's agent port. |
EXPRESSOTS_STUDIO_DB | .studio/studio.db | Path to the SQLite recording file. Add .studio/ to your .gitignore. |
EXPRESSOTS_STUDIO_DEBUG | (unset) | Set to true to print verbose [Studio] ... startup logs. |
CLI commands
npx expressots-studio [command] [options]
| Command | Description |
|---|---|
start | Default (alias s). Starts the UI and probes the agent. |
info | Prints discovered routes and project structure from your src/. |
clean | Deletes the SQLite recording. |
emit-openapi | Generates an OpenAPI 3.1 document from a static scan of your src/. |
Common options (start)
| Option | Default | Description |
|---|---|---|
-p, --port <port> | 3333 | UI port. |
-a, --agent-port <port> | 3334 | Agent WebSocket port. |
-d, --db-path <path> | .studio/studio.db | Path to the SQLite recording. |
--src <path> | ./src | Source directory to scan. |
--no-browser | (browser opens) | Don't open the browser automatically. |
--standalone | false | Run in standalone mode (starts own agent). |
.gitignore
The agent writes a SQLite file and a security cache under .studio/. Add the folder to your .gitignore:
# ExpressoTS Studio (local-only)
.studio/
Troubleshooting
"Studio Agent listening" line never appears
-
Confirm
@expressots/studio-agentis innode_modules:ls node_modules/@expressots/studio-agent -
Confirm you're running in development mode:
echo $NODE_ENV # should be "development" or empty -
Run with debug logs:
EXPRESSOTS_STUDIO_DEBUG=true npm run devYou should see
[Studio] Resolved studio-agent at: ...followed by[Studio] Attempting dynamic import....
"EADDRINUSE" on the agent port
The agent retries the port a few times, then logs a warning. Either kill the old process or change the port:
EXPRESSOTS_STUDIO_PORT=3344 npm run dev
…and start the UI with the matching port:
npx expressots-studio --agent-port 3344
Peer dependency warning
If you see npm WARN ... @expressots/adapter-express complaining about @expressots/studio-agent peer dependency, ensure both adapter-express and studio-agent are on the same v4 line. Studio v4.0.x pairs with adapter-express v4.0.x.
Request recording (Replay) requires Node 22.5+
Request recording is backed by Node's built-in SQLite module (node:sqlite), which is available from Node 22.5. Studio no longer ships a native dependency, so there is nothing to compile and no package-manager build approval to grant (this is what previously caused Could not locate the bindings file errors under pnpm v10+ and bun).
On Node versions older than 22.5, the agent starts normally and every Studio feature works except request recording and the Replay tab, which stay disabled. You'll see this one-time line at startup:
StudioAgent: request recording disabled (node:sqlite unavailable, requires Node >=22.5). All other Studio features remain active.
To enable recording, upgrade to Node 22.5 or newer (Node 24.15+ is fully stable and emits no experimental notices). On Node 22.x the agent suppresses the SQLite experimental warning automatically so your dev console stays clean.