Select spec version:

Reverse ETL Connection YAML Reference

Beta
Complete YAML reference for retl-connections resources in Rudder CLI, including sync configuration, mapping flows, supported destinations, and validation rules.
Available Plans
  • free
  • growth
  • enterprise

This guide is the YAML reference for Reverse ETL connection resources in a Rudder CLI project.

Reverse ETL connection support is experimental and requires Rudder CLI v0.27.0 or later.

See Enable Reverse ETL connection support for the flags to set before you validate or apply these specs.

Overview

Set kind to retl-connections and version to rudder/v1. spec.connections is a list. Each entry is one Reverse ETL source to destination link, together with its sync configuration. Store the files anywhere under the project root.

Each source must reference a supported Reverse ETL source, and each destination a supported destination. Unlike Event Stream connections, every entry needs a config block.

Each connection uses one of two mapping flows: object mapping if config.object is set (the dashboard’s Visual Data Mapper), JSON mapper otherwise (the JSON Data Mapper). See Mapping flows. The destination spec must set connection_mode.warehouse; see Destination requirements.

Rudder CLI rejects keys it doesn’t recognize at every level of the spec, so a misspelled key fails validation instead of being ignored.

Examples

This connection syncs a SQL model to an HTTP Webhook destination every 30 minutes, sending each row as an identify event:

yaml
version: rudder/v1
kind: retl-connections
metadata:
  name: retl-connections
spec:
  connections:
    - id: users-to-webhook
      source: "#retl-source-sql-model:users-model"
      destination: "#destination:my-http-destination"
      enabled: true
      config:
        sync_behaviour: upsert
        schedule:
          type: basic
          every_minutes: 30
        identifiers:
          - from: user_id
            to: user_id
        mappings:
          - from: email
            to: traits.email
        event:
          type: identify

Connection fields

Each entry in spec.connections has these fields:

PropertyType
Description
id
Required
StringLocal identifier. Must be unique across Reverse ETL connection entries in the project. Don’t change it after the first apply.
source
Required
StringReference to a Reverse ETL source in this project — #retl-source-sql-model:[source.id]. See Supported sources.
destination
Required
StringReference to a destination in this project — #destination:[destination.id].
enabledBooleanWhether this connection syncs. Defaults to true. Both the source and the destination must also be enabled for the connection to sync; validate warns if they are not.
config
Required
ObjectSync configuration for the connection. See Sync configuration.

Changing source or destination replaces the connection (delete + create). The backend allows only one connection per source–destination pair. See Apply and replace behavior.

Sync configuration

The config object has these fields:

PropertyType
Description
sync_behaviour
Required
StringSync mode — one of upsert, mirror, or full. mirror needs the object mapping flow. A table source on s3 accepts only upsert.

Immutable after the connection is created.
schedule
Required
ObjectWhen the connection syncs. See Schedule.
identifiers
Required
ArrayOne or more from/to pairs that map a warehouse column to a record identifier. In the JSON mapper flow, every to must be user_id or anonymous_id. In the object mapping flow, supply exactly one entry whose to is the destination field that identifies a record. See Mapping flows.
mappingsArrayfrom/to pairs that map a warehouse column to a destination field. Required in the JSON mapper flow.
constantsArraykey/value pairs sent with every synced record. Both are required and must be non-empty strings, so quote a number or a boolean. JSON mapper flow only.
eventObjectThe event that RudderStack sends for each record. Defaults to identify. JSON mapper flow only. See Event.

Immutable after the connection is created.
objectStringThe destination object to sync to. Setting it selects the object mapping flow. It must be non-empty and carry no leading or trailing whitespace — object: "" fails validation rather than falling back to the JSON mapper flow.

Immutable after the connection is created.
cursor_columnStringWarehouse column used for incremental syncs. Valid only when sync_behaviour is upsert.

Immutable after the connection is created.
sync_settingsObjectSync log and retry settings. See Sync settings.

To change a field marked immutable, see Change an immutable field.

Every from value, cursor_column, and event.name_column is a warehouse column name. It must start with a letter or an underscore, followed by letters, digits, underscores, $, or ..

A constants entry can’t use context.mappedToDestination as its key. RudderStack sets that key itself.

Schedule

The schedule object sets the sync schedule:

PropertyType
Description
type
Required
StringOne of basic, cron, or manual.
every_minutesIntegerInterval between syncs, in minutes. Required when type is basic, and not allowed otherwise. The minimum is 5.
cron_expressionStringCron expression for the schedule. Required when type is cron, and not allowed otherwise. See Cron expressions.

A manual schedule takes no other fields. The connection syncs only when you trigger it.

Quote a cron expression. YAML treats a leading * or @ as syntax, so an unquoted */10 * * * * or @hourly fails with a YAML parse error:

yaml
schedule:
  type: cron
  cron_expression: "*/10 * * * *"

Event

The event object applies to the JSON mapper flow:

PropertyType
Description
type
Required
StringOne of identify or track.
nameStringFixed event name. You can’t set it together with name_column.
name_columnStringWarehouse column that holds the event name. You can’t set it together with name.

If you omit event, RudderStack sends identify events. Rudder CLI also accepts a track event with neither name nor name_column, but RudderStack has no default event name, so set one. event is immutable, so set it when you create the connection.

This track event reads its name from a column, and a constant adds a fixed value to every record:

yaml
config:
  event:
    type: track
    name_column: event_name
  constants:
    - key: properties.source
      value: warehouse

See Sync Data from Reverse ETL Sources for how RudderStack sends records as identify and track events.

Sync settings

The sync_settings object controls sync observability. Every field is optional:

PropertyTypeDefault
Description
sync_logs.enabledBooleantrueWhether RudderStack stores the sync logs in your warehouse.
sync_logs.retention_daysInteger30Number of days RudderStack keeps the sync logs.
sync_logs.snapshots_to_retainInteger5Number of snapshot tables RudderStack keeps.
failed_keys.retryBooleantrueWhether RudderStack retries failed records in later syncs.
yaml
config:
  sync_settings:
    sync_logs:
      enabled: true
      retention_days: 7
      snapshots_to_retain: 3
    failed_keys:
      retry: false

Omitted and removed fields behave as follows:

  • Omitting sync_settings keeps all four defaults.
  • A partial block takes the default for every field you leave out. For example, setting only retention_days: 7 keeps sync logs enabled with five snapshots, and keeps retries on.
  • false and 0 are real settings, not omissions. Rudder CLI sends them as written.
  • Removing a block that held non-default values resets the stored settings to the defaults on the next apply.
  • A table source on s3 doesn’t support sync_settings.

Mapping flows

A connection maps data in one of two flows. No field names the flow. Rudder CLI derives it from whether object is set.

JSON mapperObject mapping
Selected whenobject is absentobject is set
DestinationsEvery supported destinationDestinations that support object mapping
identifiersOne or more, each with to set to user_id or anonymous_idExactly one, with to set to the destination field that identifies a record
mappingsRequiredOptional
constantsAllowedNot allowed
eventAllowedNot allowed
mirror sync modeNot availableAvailable

A mappings entry can’t target a field that the flow reserves for identifiers:

FlowReserved to values
JSON mapperuser_id, anonymous_id
Object mappinguser_id, context.externalId[0].id

Supported sources

SourceReferenceNotes
SQL model#retl-source-sql-model:[source.id]Any warehouse type a SQL model supports.
Table source#retl-source-table:[source.id]Experimental. Also set RUDDERSTACK_X_RETL_TABLE_SUPPORT=true (config key flags.retlTableSupport). Without it, Rudder CLI doesn’t recognize the retl-source-table kind. See Rudder CLI Validation Rules for example table source specs.

Reverse ETL sources created from Audiences aren’t supported.

Supported destinations

A Reverse ETL connection can target these destination types. All of them support the JSON mapper flow. In Rudder CLI v0.27.0, you can connect only HTTP Webhook. The others need v0.28.0 or later.

DestinationtypeObject mapping
ActiveCampaignactive_campaignNo
Amazon S3s3No
AmplitudeamYes
Attentive Tagattentive_tagNo
BigQuery StreambqstreamNo
BrazebrazeYes
Facebook Conversionsfacebook_conversionsNo
Facebook Pixelfacebook_pixelNo
Google Analytics 4ga4No
Google Cloud StoragegcsNo
HTTP WebhookhttpNo
HubSpothsYes
IterableiterableYes
MixpanelmpNo
PostHogposthogNo
TikTok Adstiktok_adsNo
WebhookwebhookNo

A destination type that doesn’t accept Reverse ETL sources fails validation. The error lists the source types the destination does accept:

destination 'my-googleads-destination' (type 'googleads') does not accept rETL sources: source type 'warehouse' is not among supported source types: web

Customer.io isn’t supported either. It syncs Reverse ETL data through its own flow, which connection specs can’t express.

Destination requirements

The destination’s config must carry a connection_mode entry for the warehouse source type, which is the source type every Reverse ETL source resolves to:

yaml
config:
  connection_mode:
    warehouse: cloud

Without it, validate reports:

destination 'my-http-destination' config has no 'connection_mode' entry for source type 'warehouse'

Some destination types need additional config keys before a Reverse ETL source can connect:

DestinationRequired config key
Brazerest_api_key
Facebook Pixelaccess_token

If the destination already has a Reverse ETL connection that you set up in the dashboard, check its spec after you upgrade to v0.28.0. See Where the mode is declared.

Cron expressions

RudderStack stores a cron_expression as written, without checking it. Rudder CLI checks it locally so that a schedule that can never run, or that runs too often, fails at validate instead of after apply.

Rudder CLI evaluates every expression in UTC. Consecutive syncs must be at least five minutes apart.

ConstructExampleResult
Five fields: minute, hour, day of month, month, day of week0 6 * * *Supported
Wildcards, lists, and ranges0,15 1-5 * * *Supported
Steps on a wildcard or a range*/10, 0-30/10Supported
Steps from a value15/20Supported
Month and day names, and name rangesJAN, mon-friSupported
? in place of *, in any field0 0 ? * MONSupported — read as *, so a ? in the minute or hour field widens the schedule and can trip the five-minute floor
Lowercase descriptors@hourly, @daily, @midnight, @weekly, @monthly, @yearly, @annuallySupported
Descriptor in any other case@DAILYError
Day of week 70 0 * * 7Error
Wrapping range22-2 * * * *Error
Wrong field count, value, or step70 * * * *Error
Six or seven fields (seconds or year)0 0 0 * * *Error
L, W, and # on the day fields0 0 L * *Error
Duration shortcuts@every 1hError
@reboot and unknown descriptors@reboot, @fortnightlyError
Date that never occurs0 0 30 2 *Error
Syncs less than five minutes apart*/2 * * * *Error
CRON_TZ= or TZ= prefixCRON_TZ=UTC 0 6 * * *Warning

An error names the problem:

'cron_expression' is not valid: consecutive syncs have a 2-minute gap; the minimum supported interval is 5 minutes

A timezone prefix is a warning because Rudder CLI can’t check the schedule it produces. The apply goes through, so verify the resulting schedule yourself.

Validation rules

rudder-cli validate runs these checks locally. Error blocks validate and apply. Warning does not.

CheckSeverity
The spec has every required field, no unrecognized keys, and valid valuesError
source and destination use #retl-source-sql-model: (or #retl-source-table:) and #destination:Error
source and destination exist in the projectError
The same source–destination pair appears only once in the projectError
The destination receives from only one Reverse ETL source in the projectError
The destination doesn’t also receive from an Event Stream source in the projectError
The destination type accepts Reverse ETL sources and doesn’t use a destination-specific flowError
The destination config includes a connection_mode entry for warehouse, and every field its definition requires for that source typeError
object is set only on a destination that supports object mappingError
identifiers, mappings, constants, and event fit the mapping flowError
sync_behaviour is supported by the source, the destination, and the mapping flowError
cursor_column is set only when sync_behaviour is upsertError
sync_settings is set only for a source that supports itError
every_minutes is at least 5Error
cron_expression is valid and syncs no more often than every five minutesError
cron_expression has no timezone prefixWarning
An enabled connection has both endpoints enabledWarning

Workspace plan gates and permissions aren’t checked locally; apply surfaces the server error. Rudder CLI also doesn’t check that object or a mapped field exists in the destination.

Topology rules see only connections in the project. Remote-only connections (created in the dashboard and never imported) are invisible at validate time.

Import existing connections

bash
rudder-cli import workspace -l <project-directory>

Enable Reverse ETL connection support before you run the import. Without it, import workspace doesn’t import Reverse ETL connections.

Import writes all importable Reverse ETL connections into one file, imported/retl/connections.yaml. Each connection’s id is generated from the names of its source and destination, for example users-model-to-users-webhook. Related SQL models land under imported/retl/sql-models/. See How to Import Workspace Resources.

Import skips a connection that a spec can’t express and leaves it unchanged in the workspace. Rudder CLI logs each skipped connection, with the reason, to ~/.rudder/cli.log. The most common reasons are:

  • Its source isn’t a supported source, or its destination isn’t a supported destination.
  • Its source is a table source, and table source support isn’t enabled.
  • Its source or destination is neither CLI-managed nor part of the same import.
  • It has no identifiers.
  • It carries settings that have no spec equivalent, such as destination-specific configuration.

If the destination is already in your project, its spec needs the connection_mode entry for warehouse before the imported connection passes validate. See Destination requirements.

The first apply after an import can fail with setting external ID for rETL connection during import: …. Run apply again, and the retry adopts the connection.

You can’t import a single Reverse ETL connection by ID. import workspace is the only import path.

See more

Questions? Let's figure it out together.

Join the RudderStack Slack community to connect with other users, customers, and the RudderStack team — or reach out for direct support.