Models

Models are the fundamental building blocks of Interlace pipelines.

What is a Model?

A model is a transformation that takes zero or more input tables and produces an output table. Models are defined using the @model decorator.

Python Models

from interlace import model
import ibis

@model(name="enriched_orders", materialise="table")
def enriched_orders(
    orders: ibis.Table,
    customers: ibis.Table
) -> ibis.Table:
    return orders.join(
        customers,
        orders.customer_id == customers.id
    ).select(
        orders.id,
        orders.amount,
        customers.name.name("customer_name")
    )

SQL Models

You can also define models in SQL files. Create models/enriched_orders.sql:

-- models/enriched_orders.sql
SELECT
    o.id,
    o.amount,
    c.name AS customer_name
FROM orders o
JOIN customers c ON o.customer_id = c.id

Interlace automatically detects dependencies by parsing table references in your SQL.

Model Options

Core

OptionTypeDefaultDescription
namestrfunction nameUnique identifier for the model
schemastr"public"Database schema/database name
connectionstrNoneNamed connection from config (defaults to first)
materialisestr"table"How to persist: table, view, ephemeral, none
strategystrNoneUpdate strategy: replace, append, merge_by_key, scd_type_2, none
primary_keystr \| list[str]NoneKey column(s) for merge/SCD strategies
dependencieslist[str]NoneExplicit dependencies (auto-detected if omitted)

Metadata

OptionTypeDefaultDescription
tagslist[str]NoneLabels for filtering, e.g. ["source"]
descriptionstrNoneHuman-readable description
ownerstrNoneOwner or team identifier

Schema & Columns

OptionTypeDefaultDescription
fieldsdictNoneSchema definition: {"col": "type"}
strictboolFalseIf True, drop columns not listed in fields
column_mappingdictNoneRename columns: {"old_name": "new_name"}
schema_modestr"safe"Evolution mode: strict, safe, flexible, lenient, ignore

Reliability & Performance

OptionTypeDefaultDescription
cachedictNoneCache policy: {"ttl": "7d", "strategy": "ttl"}
retry_policyRetryPolicyNoneRetry config for transient failures
cursorstrNoneCursor column for incremental processing

Scheduling & Export

OptionTypeDefaultDescription
scheduledictNoneSchedule: {"cron": "0 * * * *"} or {"every_s": "600"}
exportdictNoneExport: {"format": "csv", "path": "output/report.csv"}
quality_checkslist[dict]NoneQuality checks: [{"type": "not_null", "column": "id"}]

Return Types

Model functions can return:

Return TypeBehaviour
ibis.TablePassed through to materialisation
pandas.DataFrameConverted to ibis table
list[dict]Converted to table
dictSingle row
NoneSide-effect model (no output)
generatorAll yielded values collected

Best Practices

  1. Keep models focused - Each model should do one thing well
  2. Use meaningful names - Model names become table names
  3. Prefer ibis operations - They compile to efficient SQL
  4. Avoid .execute() - Let Interlace handle execution