docs

Deployments

How Unhandled detects releases from service.version, accepts declarations from CI, merges the two, and marks deployments on charts.

A deployment is a point in time where a service started running a new version in one environment. Unhandled records deployments in two ways: it detects them from the service.version your services already send, and it accepts declarations from your CI pipeline. Both land in the same history, so you can line up a latency jump or a new issue with the release that caused it.

Open Deployments in the project sidebar to see the history. Filter it by service, source (Detected from telemetry, Declared via API, Declared via CLI), version or commit SHA. The list follows the environment picker and shows 50 deployments per page.

Each row has a 5xx impact column: the change in the service's 5xx rate in the hour after the deployment against the hour before, in percentage points. It shows a dash when either hour has fewer than 30 requests.

Above the list, Running now shows the versions each service reported on its entry spans in the last 15 minutes, with each version's share of HTTP traffic and the service's last deployment. When no version shows, it says why: detection is paused, the version is a placeholder, entry spans carry no service.version, or the service sent no traces in that time.

Detected deployments

Detection needs nothing beyond the service.version resource attribute. Every minute a background job reads the entry spans of each service and environment, grouped by minute. An entry span is the first span a service records for a unit of work: a root span, or a server or consumer span whose parent lives in another process.

For each minute the job looks for a dominant version: one with at least 2 entry spans and more than half of the entry spans in that minute.

  • The first version Unhandled ever sees for a service and environment becomes the baseline. It creates no deployment.
  • When a different version becomes dominant, Unhandled records a deployment. The timestamp is when that version first appeared, as long as it appeared in the last 15 minutes and after the previous version took over. Otherwise it is the first span of the version in that minute.
  • A rollback is a deployment too. If an older version takes most of the traffic back, it is recorded again.
  • A version with fewer than 2 entry spans in a minute is ignored, so a few stray requests to an old instance do not register.
  • Versions running side by side during a rolling deploy create one deployment, when the new version takes the majority.

The job processes minutes up to 2 minutes ago to give late spans time to arrive. Services that only send logs have no entry spans and get no detected deployments.

Versions that are ignored

These values of service.version are treated as missing: 0.0.0, 0.0.1, 1.0.0, unknown, dev and latest. Many frameworks ship one of them as a default, and treating it as a release would produce noise.

Heads up. If your real first release is 1.0.0, detection will not see it. Declare it from CI, or start your version scheme elsewhere.

Churn pause

Preview environments and per-commit builds can produce a new version every few minutes. When more than 20 new versions show up for one service and environment within 60 minutes, detection pauses for that service. It resumes 60 minutes after the last new version. Declarations from CI are still accepted while detection is paused.

Commits

If your spans carry the vcs.ref.head.revision resource attribute with a full 40 character SHA, Unhandled stores it on the detected deployment. Declarations can then match on the commit instead of the version.

Declared deployments

Declarations come from your CI pipeline through the Deployments API or the unhandled deploy command. They carry what telemetry cannot: the status of the rollout, who triggered it, the CI run URL, the repository and free-form metadata.

Declarations authenticate with a deploy key, not with a service DSN. Admins create deploy keys under Settings > Deploy keys for each project (/o/:org/projects/:project/deploy-keys). A key starts with dk_ and is shown once, right after you create it. After that the list shows its name, last four characters, when it was last used and when it was created. Revoking a key stops it immediately.

Deploy keys can declare deployments and upload source maps. They cannot send telemetry, which keeps the blast radius small if a CI secret leaks. The reverse also holds: DSN keys are rejected by the deployments and source map endpoints, because DSNs can end up inside browser bundles.

Merging

When you declare a deployment and Unhandled also detects it, you get one entry instead of two. A declaration and a detected deployment merge when all of these hold:

  • Same service name and environment.
  • The detected release was first observed within 60 minutes of the declared start time, before or after.
  • The version matches, or the commit SHA matches.

The order does not matter. A declaration that arrives first is completed when telemetry catches up, and a declaration that arrives later attaches to the detected entry. The merged deployment shows as Declared and keeps its first-observed time, but charts and the history place it at the declared start time. The history page notes that the declaration was merged with the detected release.

Chart markers

Deployments appear as markers on the time series charts of the Overview, the app dashboards (Requests, Queries, External Calls, Jobs, Cache, Emails, Commands), Traces, Logs, Exceptions, issue pages and alert detail pages. A filled marker is a declared deployment; an outlined marker is a detected one. Hover a marker to see the service and version.

Failed and canceled deployments stay in the history but get no marker, since nothing changed in production. Charts show at most 500 markers per range. Each chart has a toggle to hide the markers, and your choice is remembered in the browser.

Deployment details

Click a deployment to open its details: source, commit (linked to the repository when one was declared), CI run, actor, external ID and the previous deployment of the same service. The timeline shows when it started, when it was first seen in telemetry and when it finished. Versions observed around this deployment lists the versions on the service's entry spans within an hour either side. Around this deployment links to Traces, Logs and Exceptions filtered to the service and version, 30 minutes either side.

The page also compares the hour before the deployment with the hour after it, for the same service:

  • Before vs after shows the 5xx error rate, P95 latency, throughput and exceptions on each side. For a deployment less than an hour old, the after side stops at the current time.
  • Endpoints that regressed lists up to 10 endpoints whose P95 rose by at least 5 ms, with 20 or more calls on each side.
  • New exceptions in this version lists up to 10 exception fingerprints first seen within 24 hours after the deployment.
  • Issues groups the issues seen in this version as New, Regressed, Still occurring, and Resolved by this deploy. Resolved means the issue occurred in the previous version and not since this deployment.

The MCP server exposes the same data through the list_deployments and get_deployment tools.