Back to Feast

Importing Features from dbt

docs/how-to-guides/dbt-integration.md

0.63.010.9 KB
Original Source

Importing Features from dbt

{% hint style="warning" %} Alpha Feature: The dbt integration is currently in early development and subject to change.

Current Limitations:

  • Supported data sources: BigQuery, Snowflake, and File-based sources only
  • Manual entity column specification required

Breaking changes may occur in future releases. {% endhint %}

This guide explains how to use Feast's dbt integration to automatically import dbt models as Feast FeatureViews. This enables you to leverage your existing dbt transformations as feature definitions without manual duplication.

Overview

dbt (data build tool) is a popular tool for transforming data in your warehouse. Many teams already use dbt to create feature tables. Feast's dbt integration allows you to:

  • Discover dbt models tagged for feature engineering
  • Import model metadata (columns, types, descriptions) as Feast objects
  • Generate Python code for Entity, DataSource, and FeatureView definitions

This eliminates the need to manually define Feast objects that mirror your dbt models.

Prerequisites

  • A dbt project with compiled artifacts (target/manifest.json)
  • Feast installed with dbt support:
bash
pip install 'feast[dbt]'

Or install the parser directly:

bash
pip install dbt-artifacts-parser

Quick Start

1. Tag your dbt models

In your dbt project, add a feast tag to models you want to import:

{% code title="models/driver_features.sql" %}

sql
{{ config(
    materialized='table',
    tags=['feast']
) }}

SELECT
    driver_id,
    event_timestamp,
    avg_rating,
    total_trips,
    is_active
FROM {{ ref('stg_drivers') }}

{% endcode %}

2. Define column types in schema.yml

Feast uses column metadata from your schema.yml to determine feature types:

{% code title="models/schema.yml" %}

yaml
version: 2
models:
  - name: driver_features
    description: "Driver aggregated features for ML models"
    columns:
      - name: driver_id
        description: "Unique driver identifier"
        data_type: STRING
      - name: event_timestamp
        description: "Feature timestamp"
        data_type: TIMESTAMP
      - name: avg_rating
        description: "Average driver rating"
        data_type: FLOAT64
      - name: total_trips
        description: "Total completed trips"
        data_type: INT64
      - name: is_active
        description: "Whether driver is currently active"
        data_type: BOOLEAN

{% endcode %}

3. Compile your dbt project

bash
cd your_dbt_project
dbt compile

This generates target/manifest.json which Feast will read.

4. List available models

Use the Feast CLI to discover tagged models:

bash
feast dbt list target/manifest.json --tag-filter feast

Output:

Found 1 model(s) with tag 'feast':

  driver_features
    Description: Driver aggregated features for ML models
    Columns: driver_id, event_timestamp, avg_rating, total_trips, is_active
    Tags: feast

5. Import models as Feast definitions

Generate a Python file with Feast object definitions:

bash
feast dbt import target/manifest.json \
    --entity-column driver_id \
    --data-source-type bigquery \
    --tag-filter feast \
    --output features/driver_features.py

This generates:

{% code title="features/driver_features.py" %}

python
"""
Feast feature definitions generated from dbt models.

Source: target/manifest.json
Project: my_dbt_project
Generated by: feast dbt import
"""

from datetime import timedelta

from feast import Entity, FeatureView, Field
from feast.types import Bool, Float64, Int64
from feast.infra.offline_stores.bigquery_source import BigQuerySource


# Entities
driver_id = Entity(
    name="driver_id",
    join_keys=["driver_id"],
    description="Entity key for dbt models",
    tags={'source': 'dbt'},
)


# Data Sources
driver_features_source = BigQuerySource(
    name="driver_features_source",
    table="my_project.my_dataset.driver_features",
    timestamp_field="event_timestamp",
    description="Driver aggregated features for ML models",
    tags={'dbt.model': 'driver_features', 'dbt.tag.feast': 'true'},
)


# Feature Views
driver_features_fv = FeatureView(
    name="driver_features",
    entities=[driver_id],
    ttl=timedelta(days=1),
    schema=[
        Field(name="avg_rating", dtype=Float64, description="Average driver rating"),
        Field(name="total_trips", dtype=Int64, description="Total completed trips"),
        Field(name="is_active", dtype=Bool, description="Whether driver is currently active"),
    ],
    online=True,
    source=driver_features_source,
    description="Driver aggregated features for ML models",
    tags={'dbt.model': 'driver_features', 'dbt.tag.feast': 'true'},
)

{% endcode %}

Multiple Entity Support

The dbt integration supports feature views with multiple entities, useful for modeling relationships involving multiple keys.

Usage

Specify multiple entity columns using repeated -e flags:

bash
feast dbt import \
  -m target/manifest.json \
  -e user_id \
  -e merchant_id \
  --tag feast \
  -o features/transactions.py

This creates a FeatureView with both user_id and merchant_id as entities, useful for:

  • Transaction features keyed by both user and merchant
  • Interaction features keyed by multiple parties
  • Association tables in many-to-many relationships

Single entity usage:

bash
feast dbt import -m target/manifest.json -e driver_id --tag feast

Requirements

All specified entity columns must exist in each dbt model being imported. Models missing any entity column will be skipped with a warning.

Generated Code

The --output flag generates code like:

python
user_id = Entity(name="user_id", join_keys=["user_id"], ...)
merchant_id = Entity(name="merchant_id", join_keys=["merchant_id"], ...)

transaction_fv = FeatureView(
    name="transactions",
    entities=[user_id, merchant_id],  # Multiple entities
    schema=[...],
    ...
)

CLI Reference

feast dbt list

Discover dbt models available for import.

bash
feast dbt list <manifest_path> [OPTIONS]

Arguments:

  • manifest_path: Path to dbt's manifest.json file

Options:

  • --tag-filter, -t: Filter models by dbt tag (e.g., feast)
  • --model, -m: Filter to specific model name(s)

feast dbt import

Import dbt models as Feast object definitions.

bash
feast dbt import <manifest_path> [OPTIONS]

Arguments:

  • manifest_path: Path to dbt's manifest.json file

Options:

OptionDescriptionDefault
--entity-column, -eEntity column name (can be specified multiple times)(required)
--data-source-type, -dData source type: bigquery, snowflake, filebigquery
--tag-filter, -tFilter models by dbt tagNone
--model, -mImport specific model(s) onlyNone
--timestamp-fieldTimestamp column nameevent_timestamp
--ttl-daysFeature TTL in days1
--exclude-columnsColumns to exclude from featuresNone
--no-onlineDisable online servingFalse
--output, -oOutput Python file pathNone (stdout)
--dry-runPreview without generating codeFalse

Type Mapping

Feast automatically maps dbt/warehouse column types to Feast types:

dbt/SQL TypeFeast Type
STRING, VARCHAR, TEXTString
INT, INTEGER, BIGINTInt64
SMALLINT, TINYINTInt32
FLOAT, REALFloat32
DOUBLE, FLOAT64Float64
BOOLEAN, BOOLBool
TIMESTAMP, DATETIMEUnixTimestamp
BYTES, BINARYBytes
ARRAY<type>Array(type)
JSON, JSONBMap (or Json if declared in schema)
VARIANT, OBJECTMap
SUPERMap
MAP<string,string>Map
STRUCT, RECORDStruct (BigQuery)
struct<...>Struct (Spark)

Snowflake NUMBER(precision, scale) types are handled specially:

  • Scale > 0: Float64
  • Precision <= 9: Int32
  • Precision <= 18: Int64
  • Precision > 18: Float64

Data Source Configuration

BigQuery

bash
feast dbt import manifest.json -e user_id -d bigquery -o features.py

Generates BigQuerySource with the full table path from dbt metadata:

python
BigQuerySource(
    table="project.dataset.table_name",
    ...
)

Snowflake

bash
feast dbt import manifest.json -e user_id -d snowflake -o features.py

Generates SnowflakeSource with database, schema, and table:

python
SnowflakeSource(
    database="MY_DB",
    schema="MY_SCHEMA",
    table="TABLE_NAME",
    ...
)

File

bash
feast dbt import manifest.json -e user_id -d file -o features.py

Generates FileSource with a placeholder path:

python
FileSource(
    path="/data/table_name.parquet",
    ...
)

{% hint style="info" %} For file sources, update the generated path to point to your actual data files. {% endhint %}

Best Practices

1. Use consistent tagging

Create a standard tagging convention in your dbt project:

yaml
# dbt_project.yml
models:
  my_project:
    features:
      +tags: ['feast']  # All models in features/ get the feast tag

2. Document your columns

Column descriptions from schema.yml are preserved in the generated Feast definitions, making your feature catalog self-documenting.

3. Review before committing

Use --dry-run to preview what will be generated:

bash
feast dbt import manifest.json -e user_id -d bigquery --dry-run

4. Version control generated code

Commit the generated Python files to your repository. This allows you to:

  • Track changes to feature definitions over time
  • Review dbt-to-Feast mapping in pull requests
  • Customize generated code if needed

5. Integrate with CI/CD

Add dbt import to your CI pipeline:

yaml
# .github/workflows/features.yml
- name: Compile dbt
  run: dbt compile

- name: Generate Feast definitions
  run: |
    feast dbt import target/manifest.json \
      -e user_id -d bigquery -t feast \
      -o feature_repo/features.py

- name: Apply Feast changes
  run: feast apply

Limitations

  • Single entity support: Currently supports one entity column per import. For multi-entity models, run multiple imports or manually adjust the generated code.
  • No incremental updates: Each import generates a complete file. Use version control to track changes.
  • Column types required: Models without data_type in schema.yml default to String type.

Troubleshooting

"manifest.json not found"

Run dbt compile or dbt run first to generate the manifest file.

"No models found with tag"

Check that your models have the correct tag in their config:

sql
{{ config(tags=['feast']) }}

"Missing entity column"

Ensure your dbt model includes the entity column specified with --entity-column. Models missing this column are skipped with a warning.

"Missing timestamp column"

By default, Feast looks for event_timestamp. Use --timestamp-field to specify a different column name.