Forge Data Entities
from Raw Sources

Forge typed entities from raw data. A Python-native dbt alternative built on Pydantic + Ibis. No SQL, no Jinja, no vendor lock-in.

pip install fyrnheim[duckdb]

Built for Python-first data teams

Typed Entities

Define business objects as Pydantic models. Type safety and validation at definition time, not runtime.

Multi-Backend

Same entity runs on DuckDB locally and deploys to BigQuery, ClickHouse, or Postgres with zero changes via Ibis.

Local Dev

Run transformations on local parquet files with DuckDB. No warehouse connection needed for development.

No SQL / No Jinja

Pure Python from entity definition to execution. Reusable functions replace SQL snippets and Jinja macros.

Four steps from raw data to insights

1

Initialize a project

terminal
$ fyr init myproject && cd myproject

Created myproject/
  created  entities/
  created  data/
  created  generated/
  created  fyrnheim.yaml
  created  entities/customers.py
  created  data/customers.parquet
2

Define an Entity as Pydantic Object

entities/customers.py
entity = Entity(
    name="customers",
    source=TableSource(..., duckdb_path="customers.parquet"),
    layers=LayersConfig(
        prep=PrepLayer(
            model_name="prep_customers",
            computed_columns=[
                ComputedColumn(name="email_hash",
                    expression=hash_email("email")),
                ComputedColumn(name="amount_dollars",
                    expression="t.amount_cents / 100.0"),
            ],
        ),
        dimension=DimensionLayer(
            model_name="dim_customers",
            computed_columns=[
                ComputedColumn(name="is_paying",
                    expression="t.plan != 'free'"),
            ],
        ),
    ),
    quality=QualityConfig(
        checks=[NotNull("email"), Unique("email_hash")]
    ),
)
3

Generate transformation code

terminal
$ fyr generate

Generating transforms from entities
  customers  generated/customers_transforms.py  written

Generated: 1 written, 0 unchanged
4

Run the pipeline

terminal
$ fyr run

Discovering entities... 1 found
Running on duckdb

  customers  prep -> dim  12 rows  0.1s  ok

Done: 1 success, 0 errors (0.2s)

Why fyrnheim over dbt?

dbt fyrnheim
Language SQL + Jinja Python
Type safety Runtime errors Pydantic validation at definition time
Local dev Needs multi-source config DuckDB on local parquet files
Backend portability Dialect-specific SQL Ibis compiles to 15+ backends
Testing Custom schema tests pytest + quality checks
Boilerplate Jinja macros, YAML configs Python functions, Pydantic models
Identity resolution Manual SQL joins Built-in identity graph (DerivedSource)
Multi-source union Manual UNION ALL UnionSource with field mapping
AI agents Limited with data models Love typed objects
Fyrnheim volcanic forge illustration