wrapped envelope, which includes the primary key of the changed row and a top-level field indicating the value of the row after the change event.
You can use changefeed options to customize message contents in order to integrate with your downstream requirements. For example, the previous state of the row, the origin cluster’s metadata, or the schema of the event payload in the message. Envelope configuration also allows you to prioritize change event metadata versus changefeed throughput.
The possible envelope fields support use cases such as:
- Auditing changes in data.
- Enabling full-fidelity changefeed messages.
- Routing events based on operation type.
- Automatically generating or synchronizing schemas in downstream consumers.
- Use case examples.
- Reference lists:
Use cases
The use case examples in the following sections emit to a Kafka sink. Review the Options table for option sink support. Each example uses the following table schema:The values that the
envelope option accepts are compatible with different , and the structure of the message will vary depending on the sink and .Audit changes in data
You can include both the previous and updated states of a row in the message envelope to support use cases like auditing or applying change-based logic in downstream systems. Use thediff option with to include the previous state of the row:
diff option adds the "before" field to the envelope containing the state of the row before the change:
"before" field contains null:
Route events based on operation type
This feature is in and subject to change. To share feedback and/or issues, contact Support.
envelope=enriched option with to include the "op" field in the envelope:
"op" field can contain:
"c"for ."u"for ."d"for .
"ts_ns" timestamp, included in the envelope when you specify only the envelope=enriched option, is the time the message was processed by the changefeed job. If you require timestamps to order messages based on the change event’s commit time, then you must specify envelope=enriched, enriched_properties=source, updated when you create the changefeed, which will include "ts_hlc" and "ts_ns" in the "source" field.
Add envelope schema fields
This feature is in and subject to change. To share feedback and/or issues, contact Support.
- Handle schema changes in downstream processing systems that require field types.
- Detect and adapt to changes in the table schema over time.
- Correctly parse and cast the data to deserialize into a different format.
- Automatically generate or synchronize schemas in downstream systems.
- Verify critical fields are present and set up alerts based on this.
envelope=enriched, enriched_properties=schema options with to include the "schema" top-level field and the schema fields and types:
Preserve the origin of data
This feature is in and subject to change. To share feedback and/or issues, contact Support.
envelope=enriched, enriched_properties=source options with to include the "source" top-level field that contains metadata for the origin cluster and the changefeed job:
Enable full-fidelity message envelopes
This feature is in and subject to change. To share feedback and/or issues, contact Support.
mvcc_timestamp, envelope=enriched, enriched_properties='source,schema', diff, updated, and key_in_value (for Kafka) options with to create a full-fidelity envelope:
Option reference
For a full list of options that modify the message envelope, refer to the following table:| Option | Description | Sink support | |
|---|---|---|---|
diff | Include a "before" field in each message, showing the state of the row before the change. Supported with wrapped or enriched envelopes. | All | |
enriched\_properties (Preview) | (Only applicable when envelope=enriched is set) Specify the type of metadata included in the message payload. Values: source, schema. | Kafka, Pub/Sub, webhook, sinkless | |
envelope=bare | Emit an envelope without the "after" wrapper. The row’s column data is at the top level of the message. Metadata that would typically be separate will be under a "\_\_crdb\_\_" field. Provides a more compact structure to the envelope. bare is the default envelope when using . When bare is used with the Avro format, "record" will replace the "after" keyword. | All | |
envelope=enriched (Preview) | Extend the envelope with additional metadata fields. With enriched\_properties, includes a "source" field and/or a "schema" field with extra context. Supported in JSON, Avro, and protobuf . | Kafka, Pub/Sub, webhook, sinkless | |
envelope=key\_only | Send only the primary key of the changed row and no value payload, which is more efficient if only the key of the changed row is needed. Not compatible with the updated option. | Kafka, sinkless | |
envelope=row | Emit the row data without any additional metadata field in the envelope. Not supported in Avro format or with the diff option. | Kafka, sinkless | |
envelope=wrapped (default) | Produce changefeed messages in a wrapped structure with metadata and row data. wrapped includes an "after" field, and optionally a "before" field if diff is used. Note: Envelopes contain a primary key when your changefeed is emitting to a sink that does not have a message key as part of its protocol. By default, messages emitting to Kafka sinks do not have the primary key field. Use the key\_in\_value option to include a primary key array field in messages emitted to . | All | |
full\_table\_name | Use the (database.schema.table) in topics, subjects, schemas, and record output instead of the default table name. Including the full table name prevents unintended behavior when the same table name is present in multiple databases. | All | |
key\_in\_value | Add a primary key array to the emitted message in Kafka sinks. This makes the primary key of a deleted row recoverable in sinks where each message has a value, but not a key. key\_in\_value is on by default in cloud storage and webhook sinks. To only emit the primary key of the changed row in Kafka sinks, use envelope=key\_only. | Kafka | |
mvcc\_timestamp | Emit the timestamp for each change event. The message envelope contains the MVCC timestamp of the changed row, even during the changefeed’s initial scan. Provides a precise database commit timestamp, which is useful for debugging or strict ordering. | All | |
resolved | Emit resolved timestamps in a format depending on the connected sink. Note: The resolved timestamp is emitted as a separate message, and has its own envelope containing a resolved key and a timestamp value as a string. For more details on the resolved options, refer to . | All | |
updated | Add an "updated" timestamp field to each message, showing the commit time of the change. When the changefeed runs an initial scan or a , the "updated" field will reflect the time of the scan or backfill, not the MVCC timestamp. If you use updated with envelope=enriched, you must also specify enriched\_properties=source, and then the "updated" field will be replaced with "ts\_ns" and "ts\_hlc" in the "source" fields. Note:envelope=enriched with the updated option will not produce a change event commit timestamp in the message—to include the timestamp, use updated with envelope=enriched, enriched\_properties=source, updated. | All |
envelope option examples
wrapped
wrapped is the default envelope structure for changefeed messages. This envelope contains an array of the primary key (or the key as part of the message metadata), a top-level field for the type of message, and the current state of the row (or NULL for ).
By default, messages emitted to Kafka sinks do not have the primary key array field. If you would like messages emitted to Kafka sinks to contain a primary key array field, you can use the option. Refer to the following message outputs for examples of this.
Cloud storage sink:
envelope=wrapped or envelope is not specified:
key_in_value provided:
enriched
This feature is in and subject to change. To share feedback and/or issues, contact Support.
enriched introduces additional metadata to the envelope, which is further configurable with the enriched_properties option. This envelope option is supported for , , , and sinkless changefeeds.
To add the operation type and the processing timestamp of the change event to the envelope, use envelope=enriched:
envelope=enriched, you must also use enriched_properties='source' with the updated option in order to include the "ts_hlc" and "ts_ns" commit timestamps in the "source" field:
envelope=enriched and enriched_properties='source,schema':
bare
bare removes the after key from the changefeed message and stores any metadata in a crdb field. When used with format, record will replace the after key.
Cloud storage sink:
bare message envelope places the output of the SELECT clause at the top level of the message instead of under an "after" key. When there is additional information that the changefeed is sending, such as or timestamps, the messages will include a crdb field containing this information.
In CDC queries:
A changefeed containing a SELECT clause without any additional options:
SELECT clause with the option specified:
key_only
key_only emits only the key and no value, which is faster if you only need to know the key of the changed row. This envelope option is only supported for or sinkless changefeeds.
Kafka sink:
It is necessary to set up a Kafka consumer to display the key because the key is part of the metadata in Kafka messages, rather than in its own field. When you start a Kafka consumer, you can use
--property print.key=true to have the key print in the changefeed message.row
row emits the row without any additional metadata fields in the message. This envelope option is only supported for or sinkless changefeeds. row does not support format—if you are using avro, refer to the bare envelope option.
Kafka sink:
Field reference
CockroachDB provides multiple changefeed envelopes, each supported by different and use cases. For the changefeed options to enable each field, refer to the following descriptions:"payload"
The top-level "payload" field is present in envelopes for changefeeds emitting to a sink and contains all of the change event data. The messages emit as a batch with a "payload" wrapper around the change event data and a "length" field for the number of messages in the batch:
"payload" with enriched envelope
When the envelope=enriched, enriched_properties=schema envelope options are specified, the envelope will include a payload field that wraps the entire message except for the "schema" fields.
As a result, when you emit messages to a webhook sink with envelope=enriched, enriched_properties=schema, you will receive messages with two "payload" fields, similar to the following structure:
"after"
The state of the row after the change. This contains the column names and values after an or . For operations, "after" will be NULL. In the default wrapped envelope, every message for an INSERT or UPDATE has an "after" field with the new data. In a row envelope, the whole message is the state of the row without the "after" wrapper, and in the key_only envelope there is no "after" field because only the key is sent.
"before"
The state of the row before the change. This field appears only if the diff option is enabled on a wrapped (or enriched) envelope. For updates, "before" is the previous values of the row before the update. For deletes, "before" is the last state of the row. For inserts, "before" will be NULL (the row had no prior state). This field is useful for auditing changes or computing differences. (Not applicable to envelopes like row or key_only, which do not support the "before" or "after" fields.)
"key"
- For non-
enrichedenvelopes: An array composed of the row’sPRIMARY KEYfield(s) (e.g.,[1]for JSON or{"id":{"long":1}}for Avro). For Kafka sinks, the primary key array field is by default off. If you would like messages emitted to Kafka sinks to contain a primary key array, you can use the option. - For
enrichedenvelopes: The primary key of the row as an object, e.g,{"id": 1}.
"updated"
A timestamp indicating when the change was committed. This field appears if the updated option is enabled. It is formatted as a string timestamp. The updated timestamp corresponds to the transaction commit time for that change. If the changefeed was started with a (at a specific past timestamp), the updated times will align with the MVCC timestamps of each row version.
"op"
The type of change operation. "c" for INSERT, "u" for UPDATE, "d" for DELETE. This field emits if envelope=enriched is enabled.
If you’re using to , we recommend using the envelope=enriched option instead for this metadata.
"source"
Metadata about the source of the change event. This is included when using envelope=enriched with enriched_properties='source' (or 'source,schema'). The "source" field includes the following fields about the cluster running the changefeed:
"changefeed_sink": The type receiving the changefeed (e.g.,"kafka","sinkless buffer")."cluster_id": The ."cluster_name": The name, ."database_name": The name of the database."db_version": The CockroachDB version."job_id": The changefeed’s ID."mvcc_timestamp": The of the change, as a string. This is CockroachDB’s timestamp for the version (a decimal number representing logical time). It is included if themvcc_timestampoption is set. Unlike"updated", which might be omitted for initial scans,"mvcc_timestamp"is always present on each message when enabled, including backfill events. This field is mainly used for low-level debugging or when exact internal timestamps are needed. ("mvcc_timestamp"will be a top-level field when the changefeed is not using theenrichedenvelope.)"node_id": The ID of the node that emitted the changefeed message."node_name": The name of the node that emitted the changefeed message."origin": The identifier for the changefeed’s origin, alwayscockroachdb."primary_keys": An array of column name(s) for the changed row."schema_name": The schema name of the changed table."source_node_locality": The of the node that emitted the changefeed messages, e.g.,"cloud=gce,region=us-east1,zone=us-east1-b"."table_name": The name of the table that changed."ts_hlc": A timestamp indicating when the change was committed. Included instead of"updated"when theenriched_properties=sourceandupdatedoptions are included at changefeed creation."ts_ns": A timestamp indicating when the change was committed. Included instead of"updated"when theenriched_properties=sourceandupdatedoptions are included at changefeed creation.
"ts_ns"
The processing time of the event by the changefeed job. This field emits if envelope=enriched is enabled.
When you’re comparing changes for ordering, it is important to ignore this top-level [ts_ns field]. Instead, if you require timestamps to order messages based on the change event’s commit time, then you must specify envelope=enriched, enriched_properties=source, updated when you create the changefeed, which will include "ts_hlc" and "ts_ns" in the "source" field.
table:
The name of the table that generated the change. This field appears in certain contexts:
- In sinkless changefeeds (those created with or
CREATE CHANGEFEED... WITH sinkless), the output includes a"table"field for each row change, because a single sinkless feed could cover multiple tables. - In the
enrichedenvelope, the is typically part of the"source"field (as"database_name","schema_name","table_name"sub-fields), rather than a separate top-level"table"field.
When a changefeed targets a table with multiple column families, the family name is appended to the table name as part of the topic. Refer to for guidance.
__crdb__
A field used by the bare envelope to carry CockroachDB metadata that would otherwise be top level. When envelope=bare, the message’s top level is the row data, so CockroachDB inserts any needed metadata (primary key, topic, timestamps, etc.) under a nested "__crdb__" object. For example:
"__crdb__": {"key": [101]} holds the primary key for the row, while the rest of the object are the row’s columns at the top level. Other metadata like "updated" timestamps or resolved timestamps would also appear inside __crdb__, if present. This field is specific to the bare envelope or other cases (like custom with SELECT) where metadata needs to be attached without interfering with the selected row data.
"schema"
The schema and type of each payload field. This is included when using envelope=enriched with enriched_properties='schema'. The "schema" field provides information needed to interpret the data. The following are present for each schema present in the envelope, depending on the configured options:
"field": The name of field."type": The type of the field. If"type"is anarray, then the"items"field defines the data type of the array elements."optional": This is a boolean field that defines whether a field may be absent in the"payload"section of the envelope depending on the configuration."name": The name of the described schema.
See more
- For more details on the file naming format for cloud storage sinks, refer to .

