# SQL Model Resources YAML Reference


> Complete reference for defining your SQL model resources using YAML configuration files.



This guide serves as a detailed reference for the CLI project YAML files that contain definitions of your Reverse ETL SQL model resources.

## Overview

In the context of the Rudder CLI (`rudder-cli`) tool, SQL model resources are defined using YAML files that specify the configuration for your [Reverse ETL SQL model sources](https://www.rudderstack.com/docs/activate/models/). These YAML files enable you to manage your SQL models through a Git-based workflow with version control and collaboration features.

The location and naming of these YAML files is flexible, as you can store the YAML files anywhere within the project's root directory or subdirectories.

**Success**

You can also group multiple SQL model resources in the same file, allowing structures that can best serve your project&#39;s requirements.

The Rudder CLI tool processes all valid YAML files within the project structure to recognize the defined resources.

The following sections detail the specific YAML formats and parameter definitions for SQL model resources.

## SQL model resources

You can define one or more SQL model resources in the YAML file by setting `kind` to `retl-source-sql-model`.

The `spec` parameter of the YAML file has the following structure:

| Property | Type | Description |
| :----| :-----| :------|
| `id` <br/> Required | String | Unique identifier for the SQL model resource within the project. This parameter must be unique across all SQL model resources. |
| `display_name` <br/> Required | String | Display name for the SQL model resource as shown in the RudderStack dashboard. |
| `primary_key` <br/> Required | String | Column name to use as the primary key for the model. This column must exist in your SQL query results. |
| `source_definition` <br/> Required | String | Warehouse type identifier. <br /><br />See [Supported warehouse types](#supported-warehouse-types) for values that you can use. |
| `enabled` <br/> Required | Boolean | Whether the SQL model resource is active. Set to `true` to enable the resource. |
| `account_id` <br/> Required | String | The account ID for the data warehouse connection. You can obtain this using `rudder-cli workspace accounts list`. |
| `description` | String | Optional description for the SQL model resource. |
| `sql` | String | Inline SQL query definition. <br /><br />Use the YAML literal block scalar `|` for multi-line queries. |
| `file` | String | Path to an external SQL file containing the query. Path is relative to the YAML file location. |

**Warning:** You must use exactly one of `sql` or `file` — they are mutually exclusive. Use `sql` for inline queries or `file` to reference external SQL files.

### Supported warehouse types

The `source_definition` field supports the following data warehouse types:

| Warehouse | `source_definition` value |
| :------| :-------|
| PostgreSQL | `postgres` |
| MySQL | `mysql` |
| Snowflake | `snowflake` |
| Amazon Redshift | `redshift` |
| Google BigQuery | `bigquery` |
| Databricks | `databricks` |
| Trino | `trino` |

### Example definitions

The following examples highlight the YAML configurations for SQL model resources defined using inline SQL and external SQL files. You can group multiple resources in the same YAML file to manage them together.

#### Inline SQL

```yaml
version: rudder/v1
kind: "retl-source-sql-model"
metadata:
  name: "product-purchases-model"
spec:
  id: "product-purchases-model"
  display_name: "Product Purchases SQL Model"
  primary_key: "user_id"
  description: "SQL model for tracking product purchases over the last 180 days"
  source_definition: "postgres"
  enabled: true
  account_id: "2rzPI1ARibivIvNH5DSpAKGTATy"
  sql: |
    SELECT
      user_id,
      event_name,
      event_type,
      timestamp,
      properties,
      product_id
    FROM
      user_events
    WHERE
      timestamp &gt;= CURRENT_DATE() - INTERVAL 180 DAY
      AND event_name = 'Product Purchased'
    ORDER BY
      timestamp DESC
```
#### External SQL file

```yaml
version: rudder/v1
kind: "retl-source-sql-model"
metadata:
  name: "user-analytics-model"
spec:
  id: "user-analytics-model"
  display_name: "User Analytics Model"
  primary_key: "user_id"
  description: "Comprehensive user analytics model"
  source_definition: "snowflake"
  enabled: true
  account_id: "2rzPI1ARibivIvNH5DSpAKGTATy"
  file: "./queries/user-analytics.sql"
```

In this example, the SQL query would be stored in a separate file at `./queries/user-analytics.sql` relative to the YAML file location.
#### With multiple resources

```yaml
version: rudder/v1
kind: "retl-source-sql-model"
metadata:
  name: "ecommerce-models"
spec:
  - id: "product-views-model"
    display_name: "Product Views Model"
    primary_key: "user_id"
    description: "Model for tracking product page views"
    source_definition: "bigquery"
    enabled: true
    account_id: "2rzPI1ARibivIvNH5DSpAKGTATy"
    sql: |
      SELECT
        user_id,
        product_id,
        view_timestamp,
        session_id
      FROM
        product_views
      WHERE
        view_timestamp &gt;= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  - id: "cart-abandonment-model"
    display_name: "Cart Abandonment Model"
    primary_key: "session_id"
    description: "Model for identifying cart abandonment events"
    source_definition: "bigquery"
    enabled: true
    account_id: "2rzPI1ARibivIvNH5DSpAKGTATy"
    file: "./queries/cart-abandonment.sql"
```

### Validation rules

<div class="vr-explorer vr-explorer--filtered" data-vr-explorer data-vr-instance="1">
<div class="vr-explorer__toolbar">
<div class="vr-explorer__toolbar-row">
<div class="vr-explorer__search-wrap">
<label class="vr-explorer__search-label" for="vr-rules-search-1">Search rules</label>
<input id="vr-rules-search-1" class="vr-explorer__search" type="search" placeholder="Search rules…" data-vr-search autocomplete="off">
</div>
<div class="vr-explorer__spec-wrap">
Spec version
<div class="vr-explorer__spec-toggle">
<button type="button" class="vr-explorer__spec-btn is-active" data-vr-spec="v1">v1</button>
<button type="button" class="vr-explorer__spec-btn" data-vr-spec="legacy">v0.1</button>
</div>
</div>
</div>
<div class="vr-explorer__toolbar-row vr-explorer__toolbar-row--filters">
<div class="vr-explorer__phase">
Filter by phase
<button type="button" class="vr-explorer__phase-btn is-active" data-vr-phase="all">All</button>
<button type="button" class="vr-explorer__phase-btn" data-vr-phase="syntactic">Syntactic</button>
<button type="button" class="vr-explorer__phase-btn" data-vr-phase="semantic">Semantic</button>
</div>
<p class="vr-explorer__count" data-vr-count data-vr-total="5">Showing <strong>5</strong> of 5 rules</p>
</div>
</div>
<div class="vr-explorer__rules"><div class="vr-rule" id="vr-rule-1-project-duplicate-urn-all" data-vr-rule data-phase="syntactic" data-spec-version="all" data-section="filtered-1" data-search="project/duplicate-urn urns must be unique across the project syntactic">
<div class="vr-rule__head">
<h4 class="vr-rule__title">URNs must be unique across the project</h4>
<div class="vr-rule__meta">
syntactic
errorAll spec versions</div>
<p class="vr-rule__id">Rule ID: <code>project/duplicate-urn</code></p>
</div><div class="vr-examples vr-examples--full-border">
<h4 class="vr-examples__heading">Examples</h4><nav>
<div class="nav nav-tabs vr-examples__tabs">
<a class="nav-item nav-link active vr-examples__tab vr-examples__tab--valid" id="nav-vr-tab-vr-rule-1-project-duplicate-urn-all-valid" data-toggle="tab" href="#vr-tab-vr-rule-1-project-duplicate-urn-all-valid">

✓
Valid

</a>
<a class="nav-item nav-link vr-examples__tab vr-examples__tab--invalid" id="nav-vr-tab-vr-rule-1-project-duplicate-urn-all-invalid" data-toggle="tab" href="#vr-tab-vr-rule-1-project-duplicate-urn-all-invalid">

✕
Invalid

</a>
</div>
</nav>
<div class="tab-content vr-examples__panels" id="nav-tab-content-vr-tab-vr-rule-1-project-duplicate-urn-all">
<div class="tab-pane fade show active vr-examples__panel vr-examples__panel--valid" id="vr-tab-vr-rule-1-project-duplicate-urn-all-valid"><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Distinct URNs across files</h4><p class="vr-example__desc">Each spec declares a different resource, so URNs do not collide.</p><div class="rs-code">
<div class="rs-code__head">
a.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: events
metadata:
  name: events-a
spec:
  events:
    - id: order_completed
      name: Order Completed</code></pre></div>
</div><div class="rs-code">
<div class="rs-code__head">
b.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: events
metadata:
  name: events-b
spec:
  events:
    - id: cart_viewed
      name: Cart Viewed</code></pre></div>
</div></div></div>
<div class="tab-pane fade vr-examples__panel vr-examples__panel--invalid" id="vr-tab-vr-rule-1-project-duplicate-urn-all-invalid"><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Same URN declared in two files</h4><p class="vr-example__desc">Both files declare the same event ID, which resolves to one URN. The rule flags each occurrence.</p><div class="rs-code">
<div class="rs-code__head">
a.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: events
metadata:
  name: events-a
spec:
  events:
    - id: order_completed
      name: Order Completed</code></pre></div>
</div><div class="rs-code">
<div class="rs-code__head">
b.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: events
metadata:
  name: events-b
spec:
  events:
    - id: order_completed
      name: Order Completed (duplicate)</code></pre></div>
</div><div class="vr-diagnostics">
<div class="vr-diagnostics__label">Diagnostics</div>
<ul class="vr-diagnostics__list"><li class="vr-diagnostics__item">
a.yaml
<code class="vr-diagnostics__ref">/spec/events/0/id</code>
duplicate URN &#39;event:order_completed&#39;
</li><li class="vr-diagnostics__item">
b.yaml
<code class="vr-diagnostics__ref">/spec/events/0/id</code>
duplicate URN &#39;event:order_completed&#39;
</li></ul>
</div></div></div>
</div></div></div>
<div class="vr-rule" id="vr-rule-1-project-manifest-inline-conflict-all" data-vr-rule data-phase="syntactic" data-spec-version="all" data-section="filtered-1" data-search="project/manifest-inline-conflict a (workspace_id, urn) must not be defined in both an import-manifest and inline metadata.import with differing remote_ids syntactic">
<div class="vr-rule__head">
<h4 class="vr-rule__title">A (workspace_id, urn) must not be defined in both an import-manifest and inline metadata.import with differing remote_ids</h4>
<div class="vr-rule__meta">
syntactic
errorAll spec versions</div>
<p class="vr-rule__id">Rule ID: <code>project/manifest-inline-conflict</code></p>
</div><div class="vr-examples vr-examples--full-border">
<h4 class="vr-examples__heading">Examples</h4><nav>
<div class="nav nav-tabs vr-examples__tabs">
<a class="nav-item nav-link active vr-examples__tab vr-examples__tab--valid" id="nav-vr-tab-vr-rule-1-project-manifest-inline-conflict-all-valid" data-toggle="tab" href="#vr-tab-vr-rule-1-project-manifest-inline-conflict-all-valid">

✓
Valid

</a>
<a class="nav-item nav-link vr-examples__tab vr-examples__tab--invalid" id="nav-vr-tab-vr-rule-1-project-manifest-inline-conflict-all-invalid" data-toggle="tab" href="#vr-tab-vr-rule-1-project-manifest-inline-conflict-all-invalid">

✕
Invalid (2 examples)

</a>
</div>
</nav>
<div class="tab-content vr-examples__panels" id="nav-tab-content-vr-tab-vr-rule-1-project-manifest-inline-conflict-all">
<div class="tab-pane fade show active vr-examples__panel vr-examples__panel--valid" id="vr-tab-vr-rule-1-project-manifest-inline-conflict-all-valid"><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Manifest and inline metadata import distinct resources</h4><p class="vr-example__desc">One resource is imported via the manifest, a different one via inline metadata. No URN appears in both, so the project is valid.</p><div class="rs-code">
<div class="rs-code__head">
events.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: events
metadata:
  name: events
  import:
    workspaces:
      - workspace_id: &#34;ws-1&#34;
        resources:
          - urn: &#34;event:cart_viewed&#34;
            remote_id: &#34;remote_b&#34;
spec:
  events:
    - id: order_completed
      name: Order Completed
    - id: cart_viewed
      name: Cart Viewed</code></pre></div>
</div><div class="rs-code">
<div class="rs-code__head">
import-manifest.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: import-manifest
metadata:
  name: import-manifest
spec:
  workspaces:
    - workspace_id: &#34;ws-1&#34;
      resources:
        - urn: &#34;event:order_completed&#34;
          remote_id: &#34;remote_a&#34;</code></pre></div>
</div></div></div>
<div class="tab-pane fade vr-examples__panel vr-examples__panel--invalid" id="vr-tab-vr-rule-1-project-manifest-inline-conflict-all-invalid"><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Same URN imported by both a manifest and inline metadata</h4><p class="vr-example__desc">The URN event:order_completed is declared in both the manifest and an inline metadata.import block — an ambiguous double import. The rule flags both locations; remove one.</p><div class="rs-code">
<div class="rs-code__head">
events.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: events
metadata:
  name: events
  import:
    workspaces:
      - workspace_id: &#34;ws-1&#34;
        resources:
          - urn: &#34;event:order_completed&#34;
            remote_id: &#34;remote_b&#34;
spec:
  events:
    - id: order_completed
      name: Order Completed</code></pre></div>
</div><div class="rs-code">
<div class="rs-code__head">
import-manifest.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: import-manifest
metadata:
  name: import-manifest
spec:
  workspaces:
    - workspace_id: &#34;ws-1&#34;
      resources:
        - urn: &#34;event:order_completed&#34;
          remote_id: &#34;remote_a&#34;</code></pre></div>
</div><div class="vr-diagnostics">
<div class="vr-diagnostics__label">Diagnostics</div>
<ul class="vr-diagnostics__list"><li class="vr-diagnostics__item">
import-manifest.yaml
<code class="vr-diagnostics__ref">/spec/workspaces/0/resources/0/urn</code>
URN &#39;event:order_completed&#39; is defined in both an import-manifest and inline metadata
</li><li class="vr-diagnostics__item">
events.yaml
<code class="vr-diagnostics__ref">/metadata/import/workspaces/0/resources/0/urn</code>
URN &#39;event:order_completed&#39; is defined in both an import-manifest and inline metadata
</li></ul>
</div></div><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Manifest URN overlaps a legacy rudder/0.1 inline local_id import</h4><p class="vr-example__desc">The events spec uses the legacy rudder/0.1 format, whose inline imports reference resources by local_id &#43; remote_id. The local_id order_completed resolves to the URN event:order_completed — the same URN the manifest imports. Legacy specs are still subject to the conflict rule, so both locations are flagged; remove the inline metadata entry.</p><div class="rs-code">
<div class="rs-code__head">
events.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/0.1
kind: events
metadata:
  name: events
  import:
    workspaces:
      - workspace_id: &#34;ws-1&#34;
        resources:
          - local_id: order_completed
            remote_id: &#34;remote_b&#34;
spec:
  events:
    - id: order_completed
      name: Order Completed</code></pre></div>
</div><div class="rs-code">
<div class="rs-code__head">
import-manifest.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: import-manifest
metadata:
  name: import-manifest
spec:
  workspaces:
    - workspace_id: &#34;ws-1&#34;
      resources:
        - urn: &#34;event:order_completed&#34;
          remote_id: &#34;remote_a&#34;</code></pre></div>
</div><div class="vr-diagnostics">
<div class="vr-diagnostics__label">Diagnostics</div>
<ul class="vr-diagnostics__list"><li class="vr-diagnostics__item">
import-manifest.yaml
<code class="vr-diagnostics__ref">/spec/workspaces/0/resources/0/urn</code>
URN &#39;event:order_completed&#39; is defined in both an import-manifest and inline metadata
</li><li class="vr-diagnostics__item">
events.yaml
<code class="vr-diagnostics__ref">/metadata/import/workspaces/0/resources/0/urn</code>
URN &#39;event:order_completed&#39; is defined in both an import-manifest and inline metadata
</li></ul>
</div></div></div>
</div></div></div>
<div class="vr-rule" id="vr-rule-1-project-metadata-syntax-valid-all" data-vr-rule data-phase="syntactic" data-spec-version="all" data-section="filtered-1" data-search="project/metadata-syntax-valid metadata syntax must be valid syntactic">
<div class="vr-rule__head">
<h4 class="vr-rule__title">Metadata syntax must be valid</h4>
<div class="vr-rule__meta">
syntactic
errorAll spec versions</div>
<p class="vr-rule__id">Rule ID: <code>project/metadata-syntax-valid</code></p>
</div><div class="vr-examples vr-examples--full-border">
<h4 class="vr-examples__heading">Examples</h4><nav>
<div class="nav nav-tabs vr-examples__tabs">
<a class="nav-item nav-link active vr-examples__tab vr-examples__tab--valid" id="nav-vr-tab-vr-rule-1-project-metadata-syntax-valid-all-valid" data-toggle="tab" href="#vr-tab-vr-rule-1-project-metadata-syntax-valid-all-valid">

✓
Valid (2 examples)

</a>
<a class="nav-item nav-link vr-examples__tab vr-examples__tab--invalid" id="nav-vr-tab-vr-rule-1-project-metadata-syntax-valid-all-invalid" data-toggle="tab" href="#vr-tab-vr-rule-1-project-metadata-syntax-valid-all-invalid">

✕
Invalid (2 examples)

</a>
</div>
</nav>
<div class="tab-content vr-examples__panels" id="nav-tab-content-vr-tab-vr-rule-1-project-metadata-syntax-valid-all">
<div class="tab-pane fade show active vr-examples__panel vr-examples__panel--valid" id="vr-tab-vr-rule-1-project-metadata-syntax-valid-all-valid"><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Metadata with only the required name</h4><p class="vr-example__desc">Minimal valid metadata: a name only.</p><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: events
metadata:
  name: my-events
spec:
  events: []</code></pre></div>
</div></div><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Metadata with a well-formed import block</h4><p class="vr-example__desc">An import block where each workspace declares workspace_id and each resource references a URN in the spec body.</p><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: events
metadata:
  name: my-events
  import:
    workspaces:
      - workspace_id: ws-123
        resources:
          - urn: &#34;event:order_completed&#34;
            remote_id: ev-remote-456
spec:
  events:
    - id: order_completed
      name: Order Completed</code></pre></div>
</div></div></div>
<div class="tab-pane fade vr-examples__panel vr-examples__panel--invalid" id="vr-tab-vr-rule-1-project-metadata-syntax-valid-all-invalid"><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Metadata missing required name</h4><p class="vr-example__desc">Every spec metadata block must declare a name.</p><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: events
metadata:
  import:
    workspaces:
      - workspace_id: ws-123
spec:
  events: []</code></pre></div>
</div><div class="vr-diagnostics">
<div class="vr-diagnostics__label">Diagnostics</div>
<ul class="vr-diagnostics__list"><li class="vr-diagnostics__item">
spec.yaml
<code class="vr-diagnostics__ref">/metadata/name</code>
&#39;name&#39; is required
</li></ul>
</div></div><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Import workspace missing required workspace_id</h4><p class="vr-example__desc">Each import workspace entry must declare a workspace_id.</p><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: events
metadata:
  name: my-events
  import:
    workspaces:
      - resources:
          - urn: &#34;event:order_completed&#34;
            remote_id: ev-remote-456
spec:
  events:
    - id: order_completed
      name: Order Completed</code></pre></div>
</div><div class="vr-diagnostics">
<div class="vr-diagnostics__label">Diagnostics</div>
<ul class="vr-diagnostics__list"><li class="vr-diagnostics__item">
spec.yaml
<code class="vr-diagnostics__ref">/metadata/import/workspaces/0/workspace_id</code>
&#39;workspace_id&#39; is required
</li></ul>
</div></div></div>
</div></div></div>
<div class="vr-rule" id="vr-rule-1-retl-sqlmodel-semantic-valid-v1" data-vr-rule data-phase="semantic" data-spec-version="v1" data-section="filtered-1" data-search="retl/sqlmodel/semantic-valid retl sql model semantic constraints must be satisfied semantic">
<div class="vr-rule__head">
<h4 class="vr-rule__title">RETL SQL model semantic constraints must be satisfied</h4>
<div class="vr-rule__meta">
semantic
error</div>
<p class="vr-rule__id">Rule ID: <code>retl/sqlmodel/semantic-valid</code></p>
</div><div class="vr-examples vr-examples--full-border">
<h4 class="vr-examples__heading">Examples</h4><nav>
<div class="nav nav-tabs vr-examples__tabs">
<a class="nav-item nav-link active vr-examples__tab vr-examples__tab--valid" id="nav-vr-tab-vr-rule-1-retl-sqlmodel-semantic-valid-v1-valid" data-toggle="tab" href="#vr-tab-vr-rule-1-retl-sqlmodel-semantic-valid-v1-valid">

✓
Valid

</a>
<a class="nav-item nav-link vr-examples__tab vr-examples__tab--invalid" id="nav-vr-tab-vr-rule-1-retl-sqlmodel-semantic-valid-v1-invalid" data-toggle="tab" href="#vr-tab-vr-rule-1-retl-sqlmodel-semantic-valid-v1-invalid">

✕
Invalid (3 examples)

</a>
</div>
</nav>
<div class="tab-content vr-examples__panels" id="nav-tab-content-vr-tab-vr-rule-1-retl-sqlmodel-semantic-valid-v1">
<div class="tab-pane fade show active vr-examples__panel vr-examples__panel--valid" id="vr-tab-vr-rule-1-retl-sqlmodel-semantic-valid-v1-valid"><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Valid SQL model with unique display_name</h4><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: retl-source-sql-model
metadata:
  name: churn-model
spec:
  id: churn-model
  display_name: Churn Risk Model
  account_id: acc-456
  primary_key: user_id
  source_definition: bigquery
  sql: SELECT user_id FROM churn_signals</code></pre></div>
</div></div></div>
<div class="tab-pane fade vr-examples__panel vr-examples__panel--invalid" id="vr-tab-vr-rule-1-retl-sqlmodel-semantic-valid-v1-invalid"><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">v1 SQL model with duplicate display_name</h4><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: retl-source-sql-model
metadata:
  name: churn-model-duplicate
spec:
  id: churn-model-duplicate
  display_name: Churn Risk Model
  account_id: acc-456
  primary_key: user_id
  source_definition: bigquery
  sql: SELECT user_id FROM churn_signals</code></pre></div>
</div><div class="vr-diagnostics">
<div class="vr-diagnostics__label">Diagnostics</div>
<ul class="vr-diagnostics__list"><li class="vr-diagnostics__item">
spec.yaml
<code class="vr-diagnostics__ref">/display_name</code>
duplicate display_name &#39;Churn Risk Model&#39; within kind &#39;retl-source-sql-model&#39;
</li></ul>
</div></div><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">V1 SQL models whose display_names differ only in case (names compare case-insensitively)</h4><div class="rs-code">
<div class="rs-code__head">
churn-lowercase.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: retl-source-sql-model
metadata:
  name: churn-model-lowercase
spec:
  id: churn-model-lowercase
  display_name: churn risk model
  account_id: acc-456
  primary_key: user_id
  source_definition: bigquery
  sql: SELECT user_id FROM churn_signals</code></pre></div>
</div><div class="rs-code">
<div class="rs-code__head">
churn.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: retl-source-sql-model
metadata:
  name: churn-model
spec:
  id: churn-model
  display_name: Churn Risk Model
  account_id: acc-456
  primary_key: user_id
  source_definition: bigquery
  sql: SELECT user_id FROM churn_signals</code></pre></div>
</div><div class="vr-diagnostics">
<div class="vr-diagnostics__label">Diagnostics</div>
<ul class="vr-diagnostics__list"><li class="vr-diagnostics__item">
churn.yaml
<code class="vr-diagnostics__ref">/display_name</code>
duplicate display_name &#39;Churn Risk Model&#39; (case-insensitive match with &#39;churn risk model&#39;) within kind &#39;retl-source-sql-model&#39;
</li><li class="vr-diagnostics__item">
churn-lowercase.yaml
<code class="vr-diagnostics__ref">/display_name</code>
duplicate display_name &#39;churn risk model&#39; (case-insensitive match with &#39;Churn Risk Model&#39;) within kind &#39;retl-source-sql-model&#39;
</li></ul>
</div></div><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">V1 SQL model referencing an account that cannot back its source_definition</h4><div class="rs-code">
<div class="rs-code__head">
account.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: account
metadata:
  name: prod-pg
spec:
  id: prod-pg
  name: Production Postgres
  account_definition_name: SOURCE_POSTGRES
  config:
    host: db.internal
    dbname: analytics
    user: rudder
    port: &#34;5432&#34;
    password: &#34;{{ .PG_PASSWORD }}&#34;</code></pre></div>
</div><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: retl-source-sql-model
metadata:
  name: churn-model
spec:
  id: churn-model
  display_name: Churn Risk Model
  account: &#34;#account:prod-pg&#34;
  primary_key: user_id
  source_definition: snowflake
  sql: SELECT user_id FROM churn_signals</code></pre></div>
</div><div class="vr-diagnostics">
<div class="vr-diagnostics__label">Diagnostics</div>
<ul class="vr-diagnostics__list"><li class="vr-diagnostics__item">
spec.yaml
<code class="vr-diagnostics__ref">/account</code>
account &#39;prod-pg&#39; is a &#39;postgres&#39; account (SOURCE_POSTGRES) and cannot back source_definition &#39;snowflake&#39;
</li></ul>
</div></div></div>
</div></div></div>
<div class="vr-rule" id="vr-rule-1-retl-sqlmodel-semantic-valid-legacy" data-vr-rule data-phase="semantic" data-spec-version="legacy" data-section="filtered-1" data-search="retl/sqlmodel/semantic-valid retl sql model semantic constraints must be satisfied semantic">
<div class="vr-rule__head">
<h4 class="vr-rule__title">RETL SQL model semantic constraints must be satisfied</h4>
<div class="vr-rule__meta">
semantic
error</div>
<p class="vr-rule__id">Rule ID: <code>retl/sqlmodel/semantic-valid</code></p>
</div><div class="vr-examples vr-examples--full-border">
<h4 class="vr-examples__heading">Examples</h4><nav>
<div class="nav nav-tabs vr-examples__tabs">
<a class="nav-item nav-link active vr-examples__tab vr-examples__tab--valid" id="nav-vr-tab-vr-rule-1-retl-sqlmodel-semantic-valid-legacy-valid" data-toggle="tab" href="#vr-tab-vr-rule-1-retl-sqlmodel-semantic-valid-legacy-valid">

✓
Valid

</a>
<a class="nav-item nav-link vr-examples__tab vr-examples__tab--invalid" id="nav-vr-tab-vr-rule-1-retl-sqlmodel-semantic-valid-legacy-invalid" data-toggle="tab" href="#vr-tab-vr-rule-1-retl-sqlmodel-semantic-valid-legacy-invalid">

✕
Invalid

</a>
</div>
</nav>
<div class="tab-content vr-examples__panels" id="nav-tab-content-vr-tab-vr-rule-1-retl-sqlmodel-semantic-valid-legacy">
<div class="tab-pane fade show active vr-examples__panel vr-examples__panel--valid" id="vr-tab-vr-rule-1-retl-sqlmodel-semantic-valid-legacy-valid"><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Valid legacy SQL model with unique display_name</h4><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/0.1
kind: retl-source-sql-model
metadata:
  name: revenue-model
spec:
  id: revenue-model
  display_name: Revenue Model
  account_id: acc-123
  primary_key: id
  source_definition: postgres
  sql: SELECT id, amount FROM revenue</code></pre></div>
</div></div></div>
<div class="tab-pane fade vr-examples__panel vr-examples__panel--invalid" id="vr-tab-vr-rule-1-retl-sqlmodel-semantic-valid-legacy-invalid"><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Legacy SQL model with duplicate display_name</h4><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/0.1
kind: retl-source-sql-model
metadata:
  name: revenue-model-copy
spec:
  id: revenue-model-copy
  display_name: Revenue Model
  account_id: acc-123
  primary_key: id
  source_definition: postgres
  sql: SELECT id, amount FROM revenue</code></pre></div>
</div><div class="vr-diagnostics">
<div class="vr-diagnostics__label">Diagnostics</div>
<ul class="vr-diagnostics__list"><li class="vr-diagnostics__item">
spec.yaml
<code class="vr-diagnostics__ref">/display_name</code>
duplicate display_name &#39;Revenue Model&#39; within kind &#39;retl-source-sql-model&#39;
</li></ul>
</div></div></div>
</div></div></div>
<div class="vr-rule" id="vr-rule-1-retl-sqlmodel-spec-syntax-valid-v1" data-vr-rule data-phase="syntactic" data-spec-version="v1" data-section="filtered-1" data-search="retl/sqlmodel/spec-syntax-valid retl sql model spec syntax must be valid syntactic">
<div class="vr-rule__head">
<h4 class="vr-rule__title">RETL SQL model spec syntax must be valid</h4>
<div class="vr-rule__meta">
syntactic
error</div>
<p class="vr-rule__id">Rule ID: <code>retl/sqlmodel/spec-syntax-valid</code></p>
</div><div class="vr-examples vr-examples--full-border">
<h4 class="vr-examples__heading">Examples</h4><nav>
<div class="nav nav-tabs vr-examples__tabs">
<a class="nav-item nav-link active vr-examples__tab vr-examples__tab--valid" id="nav-vr-tab-vr-rule-1-retl-sqlmodel-spec-syntax-valid-v1-valid" data-toggle="tab" href="#vr-tab-vr-rule-1-retl-sqlmodel-spec-syntax-valid-v1-valid">

✓
Valid (2 examples)

</a>
<a class="nav-item nav-link vr-examples__tab vr-examples__tab--invalid" id="nav-vr-tab-vr-rule-1-retl-sqlmodel-spec-syntax-valid-v1-invalid" data-toggle="tab" href="#vr-tab-vr-rule-1-retl-sqlmodel-spec-syntax-valid-v1-invalid">

✕
Invalid (3 examples)

</a>
</div>
</nav>
<div class="tab-content vr-examples__panels" id="nav-tab-content-vr-tab-vr-rule-1-retl-sqlmodel-spec-syntax-valid-v1">
<div class="tab-pane fade show active vr-examples__panel vr-examples__panel--valid" id="vr-tab-vr-rule-1-retl-sqlmodel-spec-syntax-valid-v1-valid"><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Valid SQL model spec with inline SQL</h4><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: retl-source-sql-model
metadata:
  name: user-orders-model
spec:
  id: user-orders-model
  display_name: User Orders
  account_id: acc-123
  primary_key: id
  source_definition: snowflake
  sql: SELECT id, name FROM orders</code></pre></div>
</div></div><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Valid v1 SQL model spec referencing an account in the project instead of an account_id</h4><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: retl-source-sql-model
metadata:
  name: user-orders-model
spec:
  id: user-orders-model
  display_name: User Orders
  account: &#34;#account:prod-snowflake&#34;
  primary_key: id
  source_definition: snowflake
  sql: SELECT id, name FROM orders</code></pre></div>
</div></div></div>
<div class="tab-pane fade vr-examples__panel vr-examples__panel--invalid" id="vr-tab-vr-rule-1-retl-sqlmodel-spec-syntax-valid-v1-invalid"><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">v1 SQL model missing required account_id</h4><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: retl-source-sql-model
metadata:
  name: user-orders-model
spec:
  id: user-orders-model
  display_name: User Orders
  primary_key: id
  source_definition: bigquery
  sql: SELECT id, name FROM orders</code></pre></div>
</div><div class="vr-diagnostics">
<div class="vr-diagnostics__label">Diagnostics</div>
<ul class="vr-diagnostics__list"><li class="vr-diagnostics__item">
spec.yaml
<code class="vr-diagnostics__ref">/account_id</code>
&#39;account_id&#39; is required when &#39;account&#39; is not specified
</li></ul>
</div></div><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">V1 SQL model specifying both account_id and account (mutually exclusive)</h4><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: retl-source-sql-model
metadata:
  name: user-orders-model
spec:
  id: user-orders-model
  display_name: User Orders
  account_id: acc-123
  account: &#34;#account:prod-snowflake&#34;
  primary_key: id
  source_definition: snowflake
  sql: SELECT id, name FROM orders</code></pre></div>
</div><div class="vr-diagnostics">
<div class="vr-diagnostics__label">Diagnostics</div>
<ul class="vr-diagnostics__list"><li class="vr-diagnostics__item">
spec.yaml
<code class="vr-diagnostics__ref">/account_id</code>
&#39;account_id&#39; and &#39;account&#39; cannot be specified together
</li></ul>
</div></div><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">v1 SQL model specifies both sql and file</h4><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/v1
kind: retl-source-sql-model
metadata:
  name: user-orders-model
spec:
  id: user-orders-model
  display_name: User Orders
  account_id: acc-123
  primary_key: id
  source_definition: postgres
  sql: SELECT id FROM orders
  file: ./query.sql</code></pre></div>
</div><div class="vr-diagnostics">
<div class="vr-diagnostics__label">Diagnostics</div>
<ul class="vr-diagnostics__list"><li class="vr-diagnostics__item">
spec.yaml
<code class="vr-diagnostics__ref">/sql</code>
&#39;sql&#39; and &#39;file&#39; cannot be specified together
</li></ul>
</div></div></div>
</div></div></div>
<div class="vr-rule" id="vr-rule-1-retl-sqlmodel-spec-syntax-valid-legacy" data-vr-rule data-phase="syntactic" data-spec-version="legacy" data-section="filtered-1" data-search="retl/sqlmodel/spec-syntax-valid retl sql model spec syntax must be valid syntactic">
<div class="vr-rule__head">
<h4 class="vr-rule__title">RETL SQL model spec syntax must be valid</h4>
<div class="vr-rule__meta">
syntactic
error</div>
<p class="vr-rule__id">Rule ID: <code>retl/sqlmodel/spec-syntax-valid</code></p>
</div><div class="vr-examples vr-examples--full-border">
<h4 class="vr-examples__heading">Examples</h4><nav>
<div class="nav nav-tabs vr-examples__tabs">
<a class="nav-item nav-link active vr-examples__tab vr-examples__tab--valid" id="nav-vr-tab-vr-rule-1-retl-sqlmodel-spec-syntax-valid-legacy-valid" data-toggle="tab" href="#vr-tab-vr-rule-1-retl-sqlmodel-spec-syntax-valid-legacy-valid">

✓
Valid

</a>
<a class="nav-item nav-link vr-examples__tab vr-examples__tab--invalid" id="nav-vr-tab-vr-rule-1-retl-sqlmodel-spec-syntax-valid-legacy-invalid" data-toggle="tab" href="#vr-tab-vr-rule-1-retl-sqlmodel-spec-syntax-valid-legacy-invalid">

✕
Invalid (2 examples)

</a>
</div>
</nav>
<div class="tab-content vr-examples__panels" id="nav-tab-content-vr-tab-vr-rule-1-retl-sqlmodel-spec-syntax-valid-legacy">
<div class="tab-pane fade show active vr-examples__panel vr-examples__panel--valid" id="vr-tab-vr-rule-1-retl-sqlmodel-spec-syntax-valid-legacy-valid"><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Valid legacy SQL model spec with inline SQL</h4><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/0.1
kind: retl-source-sql-model
metadata:
  name: user-orders-model
spec:
  id: user-orders-model
  display_name: User Orders
  account_id: acc-123
  primary_key: id
  source_definition: postgres
  sql: SELECT id, name FROM orders</code></pre></div>
</div></div></div>
<div class="tab-pane fade vr-examples__panel vr-examples__panel--invalid" id="vr-tab-vr-rule-1-retl-sqlmodel-spec-syntax-valid-legacy-invalid"><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Legacy SQL model missing required display_name</h4><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/0.1
kind: retl-source-sql-model
metadata:
  name: user-orders-model
spec:
  id: user-orders-model
  account_id: acc-123
  primary_key: id
  source_definition: postgres
  sql: SELECT id, name FROM orders</code></pre></div>
</div><div class="vr-diagnostics">
<div class="vr-diagnostics__label">Diagnostics</div>
<ul class="vr-diagnostics__list"><li class="vr-diagnostics__item">
spec.yaml
<code class="vr-diagnostics__ref">/display_name</code>
&#39;display_name&#39; is required
</li></ul>
</div></div><div class="vr-example__item">
<h4 class="vr-examples__heading vr-examples__heading--example">Legacy SQL model with unsupported source_definition</h4><div class="rs-code">
<div class="rs-code__head">
spec.yaml
yaml
<button class="rs-code__copy" type="button">

Copy
</button>
</div>
<div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">version: rudder/0.1
kind: retl-source-sql-model
metadata:
  name: user-orders-model
spec:
  id: user-orders-model
  display_name: User Orders
  account_id: acc-123
  primary_key: id
  source_definition: oracle
  sql: SELECT id FROM orders</code></pre></div>
</div><div class="vr-diagnostics">
<div class="vr-diagnostics__label">Diagnostics</div>
<ul class="vr-diagnostics__list"><li class="vr-diagnostics__item">
spec.yaml
<code class="vr-diagnostics__ref">/source_definition</code>
&#39;source_definition&#39; must be one of [postgres redshift snowflake bigquery mysql databricks trino]
</li></ul>
</div></div></div>
</div></div></div>
</div>
</div>

## Best practices

When defining SQL model resources in YAML files, follow these best practices:

### File organization

- **Logical grouping**: Group related SQL models in the same YAML file when they share similar purposes or data sources.
- **Clear naming**: Use descriptive file names that reflect the models' purpose, such as `user-analytics-models.yaml` or `ecommerce-models.yaml`.
- **Directory structure**: Organize SQL files in subdirectories (like `./queries/` or `./sql/`) to keep your project structure clean.

### Resource configuration

- **Unique IDs**: Choose clear, descriptive IDs that reflect the model's purpose and avoid conflicts.
- **Meaningful names**: Use display names that clearly describe what the model does for dashboard users.
- **Documentation**: Always include descriptions to help team members understand the model's purpose.
- **External files**: For complex queries, use the `file` option to keep SQL in separate files for better syntax highlighting and version control. When importing resources, use the `--sql-location` parameter if you prefer external SQL files.

### Environment management

- **Variable substitution**: Substitute `account_id` values across environments with [How to Use Variable Substitution in Rudder CLI](https://www.rudderstack.com/docs/rudder-cli/variable-substitution/).
- **Environment-specific configurations**: Maintain separate configuration files or use templating for environment-specific settings.

### Query optimization

- **Primary key selection**: Choose primary keys that are unique, stable, and efficiently indexed in your warehouse.
- **Performance considerations**: Write efficient queries that minimize warehouse compute costs and execution time.
- **Data freshness**: Include appropriate date filters to control data volume and ensure relevance.

## See also

- [Create New SQL Model Resources](https://www.rudderstack.com/docs/rudder-cli/sql-models/create/)
- [Import Existing SQL Model Resources](https://www.rudderstack.com/docs/rudder-cli/sql-models/import/)
- [Validate and Preview Your Models](https://www.rudderstack.com/docs/rudder-cli/sql-models/validate/)
- [Manage SQL Models using Rudder CLI](https://www.rudderstack.com/docs/rudder-cli/sql-models/) for feature overview 
- [End-to-End Walkthrough: SQL Models with Rudder CLI](https://www.rudderstack.com/docs/rudder-cli/sql-models-walkthrough/) for an end-to-end tutorial
- [How to Use Variable Substitution in Rudder CLI](https://www.rudderstack.com/docs/rudder-cli/variable-substitution/) for `account_id` substitution
- [Reverse ETL Connection YAML Reference](https://www.rudderstack.com/docs/rudder-cli/yaml-retl-connections/) for connecting a SQL model to a destination

