---
title: "Sentry Conventions"
description: "How to add, release, and deploy semantic convention attributes across sentry-conventions, Relay, Snuba, and Sentry."
url: https://develop.sentry.dev/engineering-practices/sentry-conventions/
---

# Sentry Conventions

[Sentry Semantic Conventions](https://github.com/getsentry/sentry-conventions) is the single source of truth for attribute names, types, PII classification, and deprecation status across all of Sentry's systems. Changes to conventions flow through a defined pipeline before they take effect in production.

For full contribution details (setup, policies, testing), see the [CONTRIBUTING.md](https://github.com/getsentry/sentry-conventions/blob/main/CONTRIBUTING.md) in the repo.

Any questions? Ask in `#discuss-conventions` on Slack.

## [Overview](https://develop.sentry.dev/engineering-practices/sentry-conventions.md#overview)

Convention changes go through four stages:

1. **Define**: Add or modify attributes in `sentry-conventions`
2. **Release**: Publish a new version to npm and PyPI
3. **Update downstream repos**: Bump the dependency in Relay, Snuba, and Sentry
4. **Register** (if needed): Make new attributes queryable or add ingestion logic in Sentry

## [sentry-conventions](https://develop.sentry.dev/engineering-practices/sentry-conventions.md#sentry-conventions)

### [Adding a new attribute](https://develop.sentry.dev/engineering-practices/sentry-conventions.md#adding-a-new-attribute)

```bash
yarn create:attribute
```

This walks you through creating the attribute JSON file in `model/attributes/`. You can also use non-interactive mode:

```bash
yarn create:attribute \
  --key my.attribute.name \
  --description "What this attribute represents" \
  --type string \
  --apply_scrubbing manual \
  --is_in_otel false \
  --visibility public \
  --examples '["example_1","example_2"]'
```

### [Deprecating an attribute](https://develop.sentry.dev/engineering-practices/sentry-conventions.md#deprecating-an-attribute)

1. Modify the existing attribute JSON: Add a `deprecation` block with `_status`, `replacement`, and `reason`.
2. Create the replacement attribute if it doesn't already exist.
3. Ensure **symmetric `alias` entries**: Every member of an alias group must list every other member. The test suite enforces this.

### [Before opening a PR](https://develop.sentry.dev/engineering-practices/sentry-conventions.md#before-opening-a-pr)

* Set `apply_scrubbing` appropriately:

  * `"manual"` (default): the attribute may contain sensitive data; scrubbing is left to the user's data scrubbing settings.
  * `"auto"`: the attribute is expected to contain sensitive data in normal use; scrubbing is applied automatically.
  * `"never"`: the attribute is not expected to contain sensitive data, and scrubbing it would break product features.

* Set `visibility` to

  * `"public"` if the attribute should be visible to sentry users (i.e. most of the time).
  * `"private"` if the attribute should not be visible in the UI (but will be returned by the debug endpoint).

* Add a `changelog` entry with `"version": "next"`.

* Run `yarn generate` to regenerate the JS and Python code.

* Run `npx vitest run` to verify all tests pass (including alias symmetry, name template validation, etc.).

### [Merge process](https://develop.sentry.dev/engineering-practices/sentry-conventions.md#merge-process)

PRs require a **3 business day grace period** after the first approval before merging. This exists because attribute names, once shipped in an SDK release, are effectively permanent. See [CONTRIBUTING.md](https://github.com/getsentry/sentry-conventions/blob/main/CONTRIBUTING.md#process) for details.

## [Releasing](https://develop.sentry.dev/engineering-practices/sentry-conventions.md#releasing)

Releasing Conventions is not just a matter of publishing a new versions. We also need to update multiple services and deploy them for the changes in the release to take effect.

### [1. Publish the new version](https://develop.sentry.dev/engineering-practices/sentry-conventions.md#1-publish-the-new-version)

1. Trigger the [Release workflow](https://github.com/getsentry/sentry-conventions/actions/workflows/release.yml) on GitHub Actions with the new version number. Almost always a **minor bump** (e.g. `0.12.0` → `0.13.0`).
2. Craft creates a `release/x.y.z` branch and opens an issue on [`getsentry/publish`](https://github.com/getsentry/publish/issues).
3. Add the **`accepted`** label on the publish issue to approve.
4. CI publishes to npm, PyPI, and GitHub Releases.
5. Wait **\~20 minutes** for the internal PyPI mirror (`pypi.devinfra.sentry.io`) to sync before updating Sentry and Snuba.

### [2. Update and Deploy Downstream Repos](https://develop.sentry.dev/engineering-practices/sentry-conventions.md#2-update-and-deploy-downstream-repos)

Convention changes don't take effect in production until the downstream repos are updated and deployed.

#### [Deployment Order](https://develop.sentry.dev/engineering-practices/sentry-conventions.md#deployment-order)

You can prepare the package bump PRs in advance in all repos but a certain deployment order is required:

* Snuba must be deployed before Relay, so that Snuba's coalescing is up to date before Relay starts normalizing attributes.
* The Sentry backend must be deployed before Relay, for additional adjustments to take effect before Relay starts normalizing attributes.
* Merge the PR bumping conventions in Relay only after Snuba and the Sentry backend are deployed.

Relay and the Sentry frontend can be deployed in any order. You don't have to immediately deploy Relay. If you need to deploy Relay urgently, reach out in `#discuss-ingest` to coordinate a deployment.

#### [Snuba](https://develop.sentry.dev/engineering-practices/sentry-conventions.md#snuba)

Snuba uses the **PyPI package**.

1. Run the [`bump-version` workflow](https://github.com/getsentry/snuba/actions/workflows/bump-version.yml) with package `sentry-conventions` and the new version. This creates a PR updating `pyproject.toml` and the lockfile.
2. Review and merge the PR once approved by a code owner.
3. Deploy Snuba.

#### [Sentry Backend](https://develop.sentry.dev/engineering-practices/sentry-conventions.md#sentry-backend)

Sentry uses the **PyPI package** and may require additional registration for new attributes.

1. Run the [`bump-version` workflow](https://github.com/getsentry/sentry/actions/workflows/bump-version.yml) with package `sentry-conventions` and the new version. This creates a PR updating `pyproject.toml` and `uv.lock`.

2. Review and merge the PR. Self-approval is permitted for simple bumps.

3. If the new attribute needs special adjustments in the Sentry UI (see below), add it to:

   * [`SPAN_ATTRIBUTE_DEFINITIONS`](https://github.com/getsentry/sentry/blob/master/src/sentry/search/eap/spans/attributes.py): maps public aliases to internal names for search resolution
   * [`SPAN_EAP_COLUMN_MAP`](https://github.com/getsentry/sentry/blob/master/src/sentry/utils/snuba.py): maps public aliases to ClickHouse column names

4. If the new attribute needs to be **extracted or transformed** from incoming data (e.g. derived server-side, or a deprecation backfill requiring type conversion), add ingestion/normalization logic in the spans consumers.

When does an attribute need Sentry code adjustments? (Steps 3 and 4)

Most new attributes don't need steps 3-4. They're sent by SDKs and flow through as-is. Deprecation backfills with `backfill` or `normalize` status are handled automatically by Relay using the conventions metadata. [Step 3](https://develop.sentry.dev/engineering-practices/sentry-conventions.md#sentry-backend) is only required when the attribute needs special adjustments in the Sentry UI.

The [`SPAN_ATTRIBUTE_DEFINITIONS`](https://github.com/getsentry/sentry/blob/master/src/sentry/search/eap/spans/attributes.py) needs an entry when:

1. The public alias differs from the internal name (e.g., public alias: span.duration -> internal name: sentry.duration\_ms)
2. The attribute needs a special search type that is not a primitive, like for example currency, byte, millisecond, percentage.
3. The attribute has a validator or normalizer (e.g., validate\_span\_id, validate\_event\_id) or value normalization (e.g., normalize\_event\_id\_strict) only runs through an explicit definition
4. The attribute has a processor (post-processing transforms on query results require an explicit definition)
5. The attribute is private (private=True restricts access to callers with the attribute in their fields\_acl; this flag only works through an explicit definition)
6. The attribute is a secondary alias (secondary\_alias=True marks compatibility aliases that shouldn't be preferred in reverse lookups)
7. The attribute has context (context=AttributeContext(brief=...) provides human-readable descriptions exposed through the API)

If none of these apply, no entry is required.

The [`SPAN_EAP_COLUMN_MAP`](https://github.com/getsentry/sentry/blob/master/src/sentry/utils/snuba.py) needs an entry when the queried field in clickhouse differs from the attribute name.

#### [Relay](https://develop.sentry.dev/engineering-practices/sentry-conventions.md#relay)

Relay uses `sentry-conventions` as a **git submodule**. The build script reads the JSON model files and generates Rust code at compile time.

1. Make sure you [set up Relay](https://github.com/getsentry/relay#development) and checked out its submodules:
   ```bash
   git submodule update --init --recursive
   ```
2. Update the submodule to the release tag:
   ```bash
   # If the submodule is not initialized yet:
   git submodule update --init relay-conventions/sentry-conventions

   cd relay-conventions/sentry-conventions
   git fetch --tags
   git checkout <version>
   cd ../..
   git add relay-conventions/sentry-conventions
   ```
3. If the release **deprecates** attributes, check for Rust compilation errors. `clippy` treats deprecated constant usage as errors. [Migrate](https://github.com/getsentry/relay/blob/6a339e47cde203ea10d2046ab956f48db4abd6cf/relay-conventions/src/lib.rs#L45-L52) to the new constant names. Not every newly added deprecation results in a compilation error. This is fine and requires no changes.
4. Add a `CHANGELOG.md` entry. If the release contains no user-observable changes, you can skip this step. But most changes are user-facing (e.g. adding an attribute with a `manual` or `never` scrubbing policy, adding/changing a name or description inference rule, etc.).
5. Open + merge PR at [`getsentry/relay`](https://github.com/getsentry/relay).

#### [Sentry Frontend](https://develop.sentry.dev/engineering-practices/sentry-conventions.md#sentry-frontend)

Sentry uses the `@sentry/conventions` package in the frontend, which just needs to be bumped:

1. Bump the package version:
   ```bash
   pnpm install @sentry/conventions@^<version>
   ```
2. Commit, open a PR, and merge it once you got approval.

Importantly, `0.x` NPM packages are not bumped to the latest minor version, despite the `^` semver operator. Therefore, we need to explicitly bump the conventions package to the latest version.
