Library Usage
The Sentry CLI can be used as a JavaScript/TypeScript library, running commands in-process without spawning a subprocess. This is useful for AI coding agents, build tools, CI scripts, and other tools that want structured Sentry data.
Installation
npm install sentryQuick Start
import createSentrySDK from "sentry";
const sdk = createSentrySDK({ token: "sntrys_..." });
// Typed methods for every CLI commandconst orgs = await sdk.org.list();const issues = await sdk.issue.list({ orgProject: "acme/frontend", limit: 5 });Typed SDK
createSentrySDK() returns an object with typed methods for every CLI command,
organized by the CLI route hierarchy:
import createSentrySDK from "sentry";
const sdk = createSentrySDK({ token: "sntrys_..." });Organizations
const orgs = await sdk.org.list();const org = await sdk.org.view({ org: "acme" });Projects
const projects = await sdk.project.list({ orgProject: "acme/" });const project = await sdk.project.view({ orgProject: "acme/frontend" });Issues
const issues = await sdk.issue.list({ orgProject: "acme/frontend", limit: 10, query: "is:unresolved", sort: "date",});
const issue = await sdk.issue.view({ issue: "ACME-123" });Events, Traces, Spans
const event = await sdk.event.view({}, "abc123...");
const traces = await sdk.trace.list({ orgProject: "acme/frontend" });const trace = await sdk.trace.view({}, "abc123...");
const spans = await sdk.span.list({}, "acme/frontend");Dashboards
const dashboards = await sdk.dashboard.list({}, "acme/");const dashboard = await sdk.dashboard.view({}, "acme/", "my-dashboard");
// Nested widget commandsawait sdk.dashboard.widget.add( { display: "line", query: "count" }, "acme/", "my-dashboard");Teams
const teams = await sdk.team.list({ orgProject: "acme/" });Authentication
await sdk.auth.login();await sdk.auth.status();const whoami = await sdk.auth.whoami();The typed SDK invokes command handlers directly — bypassing CLI string parsing for zero overhead beyond the command's own logic.
Escape Hatch: run()
For commands not easily expressed through the typed API, or when you want to
pass raw CLI flags, use sdk.run():
// Run any CLI command — returns parsed JSON by defaultconst version = await sdk.run("--version");const issues = await sdk.run("issue", "list", "-l", "5");const help = await sdk.run("help", "issue");Authentication
The token option provides an auth token for the current invocation. When
omitted, it falls back to environment variables and stored credentials:
tokenoption (highest priority)SENTRY_AUTH_TOKENenvironment variableSENTRY_TOKENenvironment variable- Stored OAuth token from
sentry auth login
// Explicit tokenconst sdk = createSentrySDK({ token: "sntrys_..." });
// Or set the env var — it's picked up automaticallyprocess.env.SENTRY_AUTH_TOKEN = "sntrys_...";const sdk = createSentrySDK();Options
All options are optional. Pass them when creating the SDK:
const sdk = createSentrySDK({ token: "...", text: true, cwd: "/my/project" });| Option | Type | Default | Description |
|---|---|---|---|
token | string | Auto-detected | Auth token for this invocation |
url | string | sentry.io | Sentry instance URL for self-hosted |
org | string | Auto-detected | Default organization slug |
project | string | Auto-detected | Default project slug |
text | boolean | false | Return human-readable text instead of parsed JSON (run() only) |
cwd | string | process.cwd() | Working directory for DSN auto-detection |
signal | AbortSignal | — | Abort signal for cancelling streaming commands |
Return Values
Typed SDK methods return parsed JavaScript objects with zero serialization
overhead (via zero-copy capture). The run() escape hatch returns parsed JSON
by default, or a trimmed string for commands without JSON support.
// Typed methods → typed returnconst issues = await sdk.issue.list({ orgProject: "acme/frontend" });// IssueListResult type with known fields
// run() → parsed JSON or stringconst version = await sdk.run("--version");// "sentry 0.21.0"Error Handling
Commands that fail throw a SentryError:
import createSentrySDK, { SentryError } from "sentry";
const sdk = createSentrySDK();
try { await sdk.issue.view({ issue: "NONEXISTENT-1" });} catch (err) { if (err instanceof SentryError) { console.error(err.message); // Clean error message (no ANSI codes) console.error(err.exitCode); // Non-zero exit code console.error(err.stderr); // Raw stderr output }}Environment Isolation
The library never mutates process.env. Each invocation creates an isolated
copy of the environment. This means:
- Your application's env vars are never touched
- Multiple sequential calls are safe
- Auth tokens passed via
tokendon't leak to subsequent calls
Comparison with Subprocess
Library (createSentrySDK()) | Subprocess (child_process) | |
|---|---|---|
| Startup | ~0ms (in-process) | ~200ms (process spawn + init) |
| Output | Parsed object (zero-copy) | String (needs JSON.parse) |
| Errors | SentryError with typed fields | Exit code + stderr string |
| Auth | token option or env vars | Env vars only |
| Node.js | >=22 required | Any version |
Requirements
- Node.js >= 22 (required for
node:sqlite) - Or Bun (any recent version)
Streaming Commands
Two commands support real-time streaming: log list --follow and dashboard view --refresh.
When using streaming flags, methods return an AsyncIterable instead of a Promise:
const sdk = createSentrySDK({ token: "sntrys_..." });
// Stream logs as they arrive (polls every 5 seconds)for await (const log of sdk.log.list({ follow: "5", orgProject: "acme/backend" })) { console.log(log);}
// Auto-refresh dashboard (polls every 30 seconds)for await (const snapshot of sdk.run("dashboard", "view", "123", "--refresh", "30")) { console.log(snapshot);}
// Stop streaming by breaking out of the loopfor await (const log of sdk.log.list({ follow: "2" })) { if (someCondition) break; // Streaming stops immediately}Cancellation
break in a for await...of loop immediately signals the streaming command to stop.
You can also pass an AbortSignal via SentryOptions for programmatic cancellation:
const controller = new AbortController();const sdk = createSentrySDK({ token: "...", signal: controller.signal });
// Cancel after 30 secondssetTimeout(() => controller.abort(), 30_000);
for await (const log of sdk.log.list({ follow: "5" })) { console.log(log);}// Loop exits when signal fires