# Table Source Resources YAML Reference

<p>This guide is a detailed reference for the CLI project YAML files that define your Reverse ETL table sources.</p>

<html lang="en">
<blockquote class="info">
  <div class="tip-quote">
    
    <div class="tip-text">Table sources require Rudder CLI v0.27.0 or later. The <code>retl-sources validate</code> and <code>retl-sources preview</code> commands support table sources from v0.28.0. In v0.28.0 and earlier, you must also enable the table source experimental flags. See <a href="https://www.rudderstack.com/docs/dev-tools/rudder-cli/retl-tables/" >Manage Reverse ETL Table Sources using Rudder CLI</a>.</div>
  </div>
</blockquote>

</html>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="overview">Overview</h2><p>A table source reads rows straight from a table in your warehouse, or from files under an S3 bucket prefix, with no SQL query in between. To sync the result of a query instead, use a <a href="https://www.rudderstack.com/docs/dev-tools/rudder-cli/yaml-sql-models/" >SQL model</a>.</p>
<p>You define a table source by setting <code>kind</code> to <code>retl-source-table</code>. Table sources use <code>version: rudder/v1</code> only. Rudder CLI rejects any other version.</p>
<p>You can store the YAML files anywhere in the project directory. Define one table source per file: <code>spec</code> must be a mapping, not a list.</p>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="table-source-resources">Table source resources</h2><p>The <code>spec</code> parameter has the following structure:</p>
<table>
  <thead>
      <tr>
          <th>Property</th>
          <th>Type</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>id</code> <br/> Required</td>
          <td>String</td>
          <td>Unique identifier for the table source within the project. Connections reference the source by this ID.</td>
      </tr>
      <tr>
          <td><code>display_name</code> <br/> Required</td>
          <td>String</td>
          <td>Name of the source in the RudderStack dashboard. It must be unique across all your Reverse ETL table and SQL model sources. The comparison ignores case, so <code>Users</code> and <code>users</code> clash.</td>
      </tr>
      <tr>
          <td><code>source_definition</code> <br/> Required</td>
          <td>String</td>
          <td>The warehouse or storage type. One of <code>postgres</code>, <code>redshift</code>, <code>snowflake</code>, <code>bigquery</code>, <code>mysql</code>, <code>databricks</code>, <code>trino</code>, or <code>s3</code>. <br /><br />This value decides which of the fields below you must set. It can&rsquo;t be changed after the source is created.</td>
      </tr>
      <tr>
          <td><code>account</code> <br/> Required, unless you set <code>account_id</code></td>
          <td>String</td>
          <td>Reference to an <a href="https://www.rudderstack.com/docs/dev-tools/rudder-cli/yaml-accounts/" >account</a> defined in the same project, in the form <code>&quot;#account:&lt;account-id&gt;&quot;</code>.</td>
      </tr>
      <tr>
          <td><code>account_id</code> <br/> Required, unless you set <code>account</code></td>
          <td>String</td>
          <td>The ID of an existing account in your workspace. Get it with <code>rudder-cli workspace accounts list</code>.</td>
      </tr>
      <tr>
          <td><code>primary_key</code></td>
          <td>String</td>
          <td>Column that uniquely identifies a row. Required for warehouse sources. Not allowed for <code>s3</code>.</td>
      </tr>
      <tr>
          <td><code>schema</code></td>
          <td>String</td>
          <td>Schema, or dataset for BigQuery, that holds the table. Required for warehouse sources. Not allowed for <code>s3</code>.</td>
      </tr>
      <tr>
          <td><code>table</code></td>
          <td>String</td>
          <td>Table to read. Required for warehouse sources. Not allowed for <code>s3</code>.</td>
      </tr>
      <tr>
          <td><code>bucket_name</code></td>
          <td>String</td>
          <td>S3 bucket to read from. Required for <code>s3</code>. Not allowed for warehouse sources.</td>
      </tr>
      <tr>
          <td><code>object_prefix</code></td>
          <td>String</td>
          <td>Key prefix of the files to read, for example <code>events/2026/</code>. Required for <code>s3</code>. Not allowed for warehouse sources.</td>
      </tr>
      <tr>
          <td><code>enabled</code></td>
          <td>Boolean</td>
          <td>Whether the source is active. <br /><br /><strong>Default value</strong>: <code>true</code></td>
      </tr>
  </tbody>
</table>
<p>Set exactly one of <code>account</code> and <code>account_id</code>.</p>

<html lang="en">
<blockquote class="info">
  <div class="tip-quote">
    
    <div class="tip-text">Table sources have no <code>description</code> field, because the Reverse ETL API doesn&rsquo;t store one for table sources.</div>
  </div>
</blockquote>

</html>
<!-- end-chunk -->
<!-- begin-chunk -->
<h3 id="fields-by-source-definition">Fields by source definition</h3><table>
  <thead>
      <tr>
          <th>Field</th>
          <th>Warehouse (<code>postgres</code>, <code>redshift</code>, <code>snowflake</code>, <code>bigquery</code>, <code>mysql</code>, <code>databricks</code>, <code>trino</code>)</th>
          <th><code>s3</code></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>id</code>, <code>display_name</code>, <code>source_definition</code></td>
          <td>Required</td>
          <td>Required</td>
      </tr>
      <tr>
          <td><code>account</code> or <code>account_id</code></td>
          <td>Exactly one</td>
          <td>Exactly one</td>
      </tr>
      <tr>
          <td><code>primary_key</code>, <code>schema</code>, <code>table</code></td>
          <td>Required</td>
          <td>Not allowed</td>
      </tr>
      <tr>
          <td><code>bucket_name</code>, <code>object_prefix</code></td>
          <td>Not allowed</td>
          <td>Required</td>
      </tr>
      <tr>
          <td><code>enabled</code></td>
          <td>Optional</td>
          <td>Optional</td>
      </tr>
  </tbody>
</table>
<!-- end-chunk -->
<!-- begin-chunk -->
<h3 id="reference-an-account">Reference an account</h3><p>An <code>account</code> reference must point to an account in the same project, and that account&rsquo;s type must match <code>source_definition</code>. For example, a <code>postgres</code> table source can&rsquo;t reference a Snowflake account.</p>
<p>Rudder CLI manages only BigQuery, PostgreSQL, and Snowflake accounts. For other warehouses and for S3, set <code>account_id</code> to the ID of an account that already exists in your workspace. Rudder CLI doesn&rsquo;t check a raw <code>account_id</code> locally.</p>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="example-definitions">Example definitions</h2><div class="rs-tabs">
	<div class="rs-tabs__list">
		<button type="button" class="rs-tabs__tab"
			id="tab-bfeacd"
		
		>Warehouse table</button>
		<button type="button" class="rs-tabs__tab"
			id="tab-cfabed"
		
		>Existing account ID</button>
		<button type="button" class="rs-tabs__tab"
			id="tab-faebcd"
		
		>S3 bucket</button>
	</div>
	
<div class="rs-tabs__panel" id="panel-bfeacd">

<div class="rs-code">
  <div class="rs-code__head">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-table
metadata:
  name: users-table
spec:
  id: users-table
  display_name: Users
  account: &#34;#account:prod-pg&#34;
  source_definition: postgres
  primary_key: id
  schema: public
  table: users
  enabled: true</code></pre></div>
</div>

</div>

<div class="rs-tabs__panel" id="panel-cfabed" hidden>

<div class="rs-code">
  <div class="rs-code__head">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-table
metadata:
  name: orders-table
spec:
  id: orders-table
  display_name: Orders
  account_id: &#34;2rzPI1ARibivIvNH5DSpAKGTATy&#34;
  source_definition: redshift
  primary_key: order_id
  schema: analytics
  table: orders</code></pre></div>
</div>

</div>

<div class="rs-tabs__panel" id="panel-faebcd" hidden>

<div class="rs-code">
  <div class="rs-code__head">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-table
metadata:
  name: events-archive
spec:
  id: events-archive
  display_name: Events Archive
  account_id: &#34;2rzPI1ARibivIvNH5DSpAKGTATy&#34;
  source_definition: s3
  bucket_name: my-analytics-bucket
  object_prefix: events/2026/</code></pre></div>
</div>

</div>

</div>

<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="validation-rules">Validation rules</h2><p><code>rudder-cli validate</code> and <code>rudder-cli apply</code> check table sources before they call the API. Every error names the field it refers to.</p>
<table>
  <thead>
      <tr>
          <th>Rule</th>
          <th>Error</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>source_definition</code> is one of the supported values</td>
          <td><code>'source_definition' must be one of [postgres redshift snowflake bigquery mysql databricks trino s3]</code></td>
      </tr>
      <tr>
          <td>Exactly one of <code>account</code> and <code>account_id</code></td>
          <td><code>'account_id' is required when 'account' is not specified</code>, or <code>'account_id' and 'account' cannot be specified together</code></td>
      </tr>
      <tr>
          <td>Warehouse sources set <code>primary_key</code>, <code>schema</code>, and <code>table</code></td>
          <td><code>'table' is required unless 'source_definition' is s3</code></td>
      </tr>
      <tr>
          <td>S3 sources don&rsquo;t set <code>primary_key</code>, <code>schema</code>, or <code>table</code></td>
          <td><code>'primary_key' is not allowed when 'source_definition' is s3</code></td>
      </tr>
      <tr>
          <td>S3 sources set <code>bucket_name</code> and <code>object_prefix</code></td>
          <td><code>'object_prefix' is required when 'source_definition' is s3</code></td>
      </tr>
      <tr>
          <td><code>display_name</code> is unique across table and SQL model sources, ignoring case</td>
          <td><code>duplicate display_name 'users' (case-insensitive match with 'Users') across RETL sources</code></td>
      </tr>
      <tr>
          <td>An <code>account</code> reference points to an account that matches <code>source_definition</code></td>
          <td><code>account 'prod-pg' is a 'postgres' account (SOURCE_POSTGRES) and cannot back source_definition 's3'</code></td>
      </tr>
  </tbody>
</table>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="update-and-delete-behavior">Update and delete behavior</h2><ul>
<li><strong>Updates</strong>: Changes to <code>display_name</code>, <code>enabled</code>, the account, <code>primary_key</code>, <code>bucket_name</code>, and <code>object_prefix</code> update the source in place.</li>
<li><strong><code>source_definition</code></strong>: Changing it fails the apply. Create a new source with a new <code>id</code> instead.</li>
<li><strong><code>schema</code> and <code>table</code></strong>: Changing either fails the apply while a destination is connected to the source, including connections you created in the dashboard. Delete the connection first, or create a new source for the new table.</li>
<li><strong>Delete</strong>: RudderStack refuses to delete a source that still has connections. If the connections are in your project, <code>rudder-cli apply</code> deletes them first. Delete connections you created outside the project in the dashboard.</li>
</ul>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="see-also">See also</h2><ul>
<li><a href="https://www.rudderstack.com/docs/dev-tools/rudder-cli/retl-tables/" >Manage Reverse ETL Table Sources using Rudder CLI</a></li>
<li><a href="https://www.rudderstack.com/docs/dev-tools/rudder-cli/yaml-retl-connections/" >Reverse ETL Connections YAML Reference</a></li>
<li><a href="https://www.rudderstack.com/docs/dev-tools/rudder-cli/yaml-sql-models/" >SQL Model Resources YAML Reference</a></li>
<li><a href="https://www.rudderstack.com/docs/dev-tools/rudder-cli/yaml-accounts/" >Account Resources YAML Reference</a></li>
</ul>

