## Resource

A **Resource** is immutable metadata that describes the entity producing telemetry. It’s the answer to one question: _who is sending this data?_ Every span, metric, and log your application emits carries the same Resource. It’s set once, when the [Tracer Provider](/content/docs/ax/concepts/otel-openinference/tracer-provider/index.html) is created, and it never changes for the lifetime of the process. Picking the right Resource attributes is what makes your traces routable and queryable downstream.

# Anatomy of a Resource

| Term | What it means |
| --- | --- |
| **Describes** | Answers the question “who is sending this telemetry?” |
| **Entity** | Service name, environment, host, pod, container — anything that identifies the producer. |
| **Immutable** | Does not change during the process lifetime. The same Resource is attached to every span, metric, and log. |
| **Metadata** | Key-value pairs. |

Resource attributes should generally follow [OpenTelemetry resource semantic conventions](https://opentelemetry.io/docs/specs/semconv/resource/) so any OTel-compatible backend can interpret them.

# Configuring a Resource

```
from opentelemetry.sdk.resources import Resource

resource = Resource.create(
    {
        # Service attributes
        "service.name": "checkout",
        "service.namespace": "acme-webstore",
        "service.version": "v1.2.3",
        "service.instance.id": "instance-12345",

# Environment / infrastructure attributes
        "deployment.environment.name": "production",
        "cloud.region": "us-east-1",

# Arize AX project routing
        "openinference.project.name": "webstore-prod",
    }
)
```

For the full set of supported parameters, see the [Resource API reference](https://opentelemetry-python.readthedocs.io/en/latest/sdk/resources.html). Always use `Resource.create(...)` rather than the class constructor `Resource(attributes=...)`. `create()` merges your attributes with the defaults from the built-in resource detectors.

# Arize AX–Specific Resource Attributes

Arize AX reads two resource attributes to route spans to the right project:

| Attribute | Status | Notes |
| --- | --- | --- |
| `openinference.project.name` | Canonical | The name of the project in Arize AX. Defined by the OpenInference resource semconv — exposed as `ResourceAttributes.PROJECT_NAME` in the `openinference.semconv.resource` Python package, and as `SEMRESATTRS_PROJECT_NAME` in `@arizeai/openinference-semantic-conventions` for JS/TS. |
| `model_id` | Legacy alias | Not part of the OpenInference semconv. The Arize AX collector accepts it as an ingest-side compatibility shim for older docs and examples. Both keys route to the same project. |

Set one of these. If you’re starting fresh, use `openinference.project.name`. If you’re maintaining an older codebase, `model_id` will continue to work.

# Environment Variables

The OpenTelemetry SDK can auto-detect Resource attributes from the environment, so you can avoid hardcoding them:

| Environment variable | Purpose |
| --- | --- |
| `OTEL_SERVICE_NAME` | Sets `service.name`. |
| `OTEL_RESOURCE_ATTRIBUTES` | Comma-separated `key=value` pairs. Sets arbitrary resource attributes. |
| `OTEL_EXPERIMENTAL_RESOURCE_DETECTORS` | Comma-separated list of built-in detectors to enable or disable. |

**Code wins over environment variables.** If you set the same key in both, the value passed to `Resource.create(...)` takes precedence. The SDK also runs **built-in resource detectors** by default — they automatically fill in host, OS, process, and other infrastructure attributes. Disable them with `OTEL_EXPERIMENTAL_RESOURCE_DETECTORS=""` if you don’t want them. For the full list, see the [OpenTelemetry SDK environment variables](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/) reference.

# Common Pitfalls

**Don’t try to change the Resource per request or per span.** Only one Resource is allowed per Tracer Provider, and it’s intentionally immutable. If you need per-request context (a user ID, a session ID, a customer tier), set it as a **span attribute** instead — see [Customize your traces](/content/docs/ax/instrument/customize-your-traces/index.html) and the [OpenInference context managers](/content/docs/ax/concepts/otel-openinference/context-managers/index.html).

A few more things that trip people up:

- **Not following semantic conventions** — using your own attribute names instead of `service.name`, `deployment.environment.name`, etc. means other tools (and Arize AX) can’t interpret them. Stick with the [resource semconv](https://opentelemetry.io/docs/specs/semconv/resource/) whenever there’s a standard key.
- **Using the class constructor `Resource(attributes=...)` instead of `Resource.create(...)`** — bypasses built-in detectors, so you lose the auto-populated host/process attributes.
- **Forgetting to set a project name** — without `openinference.project.name` (or the `model_id` alias), spans land in the default project and are hard to organize.

# Where Resource Fits in the Pipeline

The Resource is held by the [Tracer Provider](/content/docs/ax/concepts/otel-openinference/tracer-provider/index.html) alongside the [Span Processor](/content/docs/ax/concepts/otel-openinference/span-processor/index.html) pipeline (which in turn owns the [Exporter](/content/docs/ax/concepts/otel-openinference/exporter/index.html)). Every span the provider hands out gets the same Resource stamped on it before export.

## Next step

The Resource describes who is sending data. The Exporter sends it:

[**Next: Exporter and OTLP**](/content/docs/ax/concepts/otel-openinference/exporter/index.html)
