﻿---
title: OpenTelemetry data streams compared to classic APM and ECS-based integrations
description: Understand how your OpenTelemetry ingest path determines the data format in Elasticsearch, and how OpenTelemetry data streams compare to classic APM and ECS-based integrations.
url: https://www.elastic.co/elastic/docs-builder/docs/4572/reference/opentelemetry/compatibility/data-streams
products:
  - Elastic Agent
  - Elastic Cloud Serverless
  - Elastic Distribution of OpenTelemetry SDK
  - Elastic Observability
applies_to:
  - Serverless Observability projects: Generally available
  - Elastic Stack: Generally available
---

# OpenTelemetry data streams compared to classic APM and ECS-based integrations
Elastic OpenTelemetry stores telemetry data using a storage model optimized for OpenTelemetry signals. When `mapping_mode: otel` is enabled on the Elasticsearch exporter (which is the default setting), Elastic OpenTelemetry writes logs, traces, and metrics to specialized data streams aligned with OpenTelemetry specifications.
This architecture is designed for scalable observability workloads. It supports dynamic attributes, reduces mapping complexity, and avoids issues like mapping explosions or manual dimension setup.
Elastic OpenTelemetry uses Elasticsearch's [Logs data stream (LogsDB)](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4572/manage-data/data-store/data-streams/logs-data-stream) and [Time Series Data Streams (TSDS)](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4572/manage-data/data-store/data-streams/time-series-data-stream-tsds) as storage backends. These are purpose-built to handle the scale and variety of observability data and improve the storage efficiency.
This page provides a detailed comparison of Elastic OpenTelemetry data streams with classic APM and ECS-based integrations. For a practical reference on which data streams Elastic OpenTelemetry uses, exporter behavior, and storage engines, see [Elastic OpenTelemetry data streams](https://www.elastic.co/elastic/docs-builder/docs/4572/reference/opentelemetry/data-streams).

## How your ingest path determines the data format

The ingest destination you choose determines how your OpenTelemetry data is stored in Elasticsearch. This affects field names, which dashboards work out of the box, and how you write queries and alerts.
Elastic Cloud Managed OTLP Endpoint, Elastic Agent configured as an OTel Collector, and the Elasticsearch OTLP/HTTP endpoint store **OTel-native** documents. APM Server and the managed intake service (the legacy `.apm` endpoint) store **ECS** documents.
```mermaid
flowchart LR
    SRC["Any OTLP source<br/>(Elastic OpenTelemetry or contrib SDKs, Collectors,<br/>Elastic Agent configured as an OTel Collector)"]:::plain

    SRC -->|OTLP| MOTLP["Elastic Cloud Managed OTLP Endpoint"]:::plain
    SRC -->|OTLP| GW["Elastic Agent configured as an OTel Collector<br/>(gateway)"]:::plain
    SRC -->|"OTLP<br/>HTTP"| ESO["Elasticsearch OTLP/HTTP endpoint"]:::plain
    SRC -.->|"OTLP<br/>(legacy<br/>path)"| APM["APM Server or the<br/>managed intake service"]:::warning

    MOTLP --> OTEL["OTel-native documents<br/>OpenTelemetry semantic conventions<br/>resource.attributes.* / attributes.*"]:::success
    GW --> OTEL
    ESO --> OTEL
    APM --> ECS["ECS documents<br/>Elastic Common Schema<br/>labels.* / numeric_labels.*"]:::note
```


| Ingest path                                                                                                                                                               | Stored format | Where the data lands                                                                                                                                                                                           |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [Elastic Cloud Managed OTLP Endpoint](https://www.elastic.co/elastic/docs-builder/docs/4572/reference/opentelemetry/managed-inputs/managed-otlp-endpoint)                 | OTel-native   | `traces-generic.otel-default`, `metrics-generic.otel-default`, `logs-generic.otel-default` by default. Routing is configurable using `data_stream.dataset` and `data_stream.namespace` attributes.             |
| [Elastic Agent configured as an OTel Collector (gateway)](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4572/reference/edot-collector/modes)              | OTel-native   | `elasticsearch` exporter with `mapping_mode: otel` (the default). Writes to `traces-*.otel-*`, `metrics-*.otel-*`, and `logs-*.otel-*`.                                                                        |
| [Elasticsearch OTLP/HTTP endpoint](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4572/manage-data/ingest/otlp-endpoint) (self-managed, ECE, and ECK only) | OTel-native   | Pattern: `<type>-<dataset>.otel-<namespace>`. Default: `traces-generic.otel-default`, `metrics-generic.otel-default`, `logs-generic.otel-default`.                                                             |
| APM Server or the managed intake service (`.apm` endpoint)                                                                                                                | ECS           | Legacy path that translates OTLP to ECS. Unmapped attributes land in `labels.*` with dots replaced by underscores. Not recommended for new users. Elastic OpenTelemetry SDKs are not supported with this path. |

<note>
  Elastic Agent can also write ECS-formatted data in two specific cases: when using the `elasticapmintake` receiver (intended for migrating classic APM agents) or when the `ecs` mapping mode is explicitly configured. Beat receivers and ECS-based integrations are outside the OTLP paths shown in this section and always produce ECS-formatted data.
</note>


### What the stored format affects

The format determines your experience across the stack:
- **Prebuilt dashboards and content packages**: Many prebuilt Elastic integrations and dashboards are designed for ECS-formatted data and may not work with OpenTelemetry semantic conventions without customization. When using OTel-native paths, install OpenTelemetry content packages from the Kibana Integrations UI (search for `otel`) to get OTel-compatible dashboards.
- **Custom queries and alerts**: Attributes and labels are stored differently. Classic APM stores custom attributes in `labels.*` (strings) and `numeric_labels.*` (numbers), with dots replaced by underscores. OTel-native paths store them in `attributes.*`, preserving dots. Queries and alerts built on one format need to be updated when switching.
- **Elasticsearch ingest pipelines**: Elasticsearch ingest pipelines cannot directly parse OTel-native data with dotted field names without preprocessing. Data from OTel-native paths bypasses ingest pipelines. Data from the `.apm` path and Beat receivers is processed by ingest pipelines in the usual way.
- **Storage engine**: OTel-native data uses [LogsDB](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4572/manage-data/data-store/data-streams/logs-data-stream) (logs and traces) and [TSDS](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4572/manage-data/data-store/data-streams/time-series-data-stream-tsds) (metrics). ECS-formatted APM data uses general-purpose data streams. Refer to [Elastic OpenTelemetry data streams](https://www.elastic.co/elastic/docs-builder/docs/4572/reference/opentelemetry/data-streams) for details.


## Logs and traces in LogsDB

Log and trace data is stored in [LogsDB](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4572/manage-data/data-store/data-streams/logs-data-stream), a storage engine optimized for high-ingest, semi-structured observability data. Benefits include:
- Storage efficiency
- Optimized field handling for dynamic fields (for example, `attributes`)


## Metrics in TSDS

Metric data is stored using Elasticsearch's [TSDS](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4572/manage-data/data-store/data-streams/time-series-data-stream-tsds). Benefits include:
- Efficient storage using columnar compression
- Fast aggregations
- Automatic detection of metric dimensions (no need to manually define `time_series_dimension` in field mappings)


## Comparison with classic APM data streams

This table highlights key differences between classic APM data streams and Elastic OpenTelemetry with `mapping_mode: otel`:

| Feature            | Classic APM (ECS-based)                                                                                                                                                                                                                                                                   | Elastic OpenTelemetry (`mapping_mode: otel`)                                                                                                    |
|--------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|
| Index mode         | General-purpose data streams (logs, traces, metrics)  TSDS is not supported for classic APM.                                                                                                                                                                                              | LogsDB (logs/traces), TSDS (metrics)                                                                                                            |
| Mapping style      | Nested objects are mapped as structured fields. Some exceptions exist, such as `labels.*` and `numeric_labels.*`, where dots in field names are replaced with underscores.  ECS supports multiple field types (keyword, long, double, date, boolean, and so on) as defined in the schema. | Native OpenTelemetry fields with `passthrough`, preserving types and structure.                                                                 |
| Attribute handling | Dynamic mapping. Custom attributes are stored under `labels.*` (strings) or `numeric_labels.*` (numbers); dots in field names are replaced with underscores.  See [Document examples - classic APM](#classic-apm)                                                                         | Dynamic mapping with native types under `attributes.*`, preserving dots in field names.  See [Document examples - Elastic OpenTelemetry](#edot) |


### Query compatibility with classic APM data streams

Elastic OpenTelemetry is designed to make OpenTelemetry data queryable using many of the same field names as classic APM (ECS-based) data streams. This helps preserve compatibility with existing dashboards, saved searches, and queries.
Query compatibility is achieved through:
- **`passthrough` fields:** Make nested OpenTelemetry fields available at the top level so they can be queried. For example, while the service name is stored at `resource.attributes.service.name`, you can query it as `service.name` (the same field name as the one used in the classic APM data stream).
- **Field aliases:** Map fields with different names in ECS and OpenTelemetry semantic conventions to a common query name to make migration easier.


#### Limitations

Query compatibility is not complete:
- Not all ECS fields have aliases. Some integration-specific fields may require query changes.
- Custom attributes and labels are stored differently.

These differences may require updates to certain queries or visualizations.
Refer to [ECS & OpenTelemetry](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4572/reference/ecs/ecs-opentelemetry) for details on the available aliases and field mappings.

### Document examples


#### Classic APM

```yaml
"@timestamp": "2025-08-14T05:29:43.922Z"
data_stream:
  type: logs
  dataset: apm.app.cart-service
  namespace: default
service:
  name: "cart-service"
host:
  ip: ["127.0.0.1", "0.0.0.0"]
kubernetes:
  namespace: "ecommerce"
labels:
  customer_id: "fc2d1b03-b307-4ae3-a19e-df2804c49fc2"
numeric_labels:
  order_id: 4711
  cart_items: 42
  cart_total_amount: 42.0
message: "Order was successfully created"
log:
  level: INFO
```


#### Elastic OpenTelemetry

```yaml
"@timestamp": "2025-08-14T05:29:43.922Z"
data_stream:
  type: logs
  dataset: generic.otel
  namespace: default
resource:
  attributes:
    service.name: "cart-service"
    host.ip: ["127.0.0.1", "0.0.0.0"]
    k8s.namespace.name: "ecommerce"
attributes:
  customer.id: "fc2d1b03-b307-4ae3-a19e-df2804c49fc2"
  order.id: 4711
  cart.items: 42
  cart.total_amount: 42.0
body:
  text: "Order was successfully created"
severity_text: INFO
```


## Comparison with ECS-based integrations

While classic APM and Elastic OpenTelemetry represent two ingestion paths for application telemetry, Elastic's integrations (for example Nginx, MySQL, Kubernetes) also produce ECS-based data streams for logs, metrics, and events. These use ECS mappings and integration-specific pipelines optimized for their domain.

| Stream type                                    | Typical field layout                                                                                                                                                                        | Custom attributes / dot notation                                                             |
|------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------|
| **Integration ECS-based**                      | Uses ECS mapping tailored by integration. Custom fields are added under ECS-structured objects or `.custom` objects. Dots in field names are often disallowed or normalized to underscores. | Example: `host.os.name`, `nginx.access.time` rewritten to `nginx_access_time`                |
| **Elastic OpenTelemetry (OTel + passthrough)** | Stores OTel-native nested object structure (`resource.attributes.*`, `attributes.*`). Uses `passthrough` to expose fields at the top level for query compatibility.                         | Example: `attributes.cart.items: 42`, `resource.attributes.service.name: "checkout-service"` |


### Integration example (Nginx access logs)

```yaml
"@timestamp": "2025-08-14T12:00:01.123Z"
event:
  dataset: nginx.access
  module: nginx
host:
  name: "web-1"
nginx:
  access:
    request: "/api/v1/items"
    status_code: 200
    bytes_sent: 512
user:
  ip: "203.0.113.45"
```


## Summary of all data stream types


| Feature                  | Classic APM (ECS-based)                                                                     | Integration ECS-based streams                                       | Elastic OpenTelemetry (`mapping_mode: otel`)                                    |
|--------------------------|---------------------------------------------------------------------------------------------|---------------------------------------------------------------------|---------------------------------------------------------------------------------|
| **Index mode**           | General-purpose data streams (logs, traces, metrics); TSDS not supported                    | ECS-style data streams (logs, metrics, events) using integrations   | LogsDB for logs/traces, TSDS for metrics                                        |
| **Mapping style**        | ECS object mappings; nested fields preserved. `labels.*` / `numeric_labels.*` flatten dots. | ECS mappings or integration-altered schemas (flattening, renaming). | OTel-native nested layout with `passthrough`, preserving types and structure.   |
| **Attribute handling**   | Custom values under `labels.*` / `numeric_labels.*`, dots replaced by underscores.          | Integration-specific or prefixed fields.                            | Custom values under `attributes.*`, dots preserved.                             |
| **Query compatibility**  | Queries target ECS field names (`service.name`, `labels.*`).                                | Queries assume ECS names; pipelines normalize vendor data.          | `passthrough` + aliases allow ECS-style names (such as `service.name`).         |
| **Compatibility limits** | N/A                                                                                         | Some integration fields may not align 1:1 with ECS or OTel.         | Not all ECS/integration fields have aliases; label vs attribute layout differs. |


## See also

- [ECS and OpenTelemetry schema reference](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4572/reference/ecs/ecs-opentelemetry)
- [Logs data stream (LogsDB)](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4572/manage-data/data-store/data-streams/logs-data-stream)
- [Time Series Data Stream (TSDS)](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/4572/manage-data/data-store/data-streams/time-series-data-stream-tsds)