models/federates/ directory and can be written in SQL (DuckDB dialect) or Python.
File structure
SQL federate models
SQL federate models use the DuckDB dialect and support full Jinja templating with access to parameters, context variables, and user information.Example SQL model
models/federates/fed_transactions_summary.sql
Available Jinja variables
The following variables are commonly used in federate models:| Variable | Description |
|---|---|
ctx | Dictionary of context variables from context.py |
ref(model_name) | Macro that returns the table name for the referenced model |
is_placeholder(name) | Check if a placeholder exists |
ctx:
| Variable | Description |
|---|---|
proj_vars | Dictionary of project variables from squirrels.yml |
env_vars | Dictionary of environment variables |
user | The authenticated user object with username and custom_fields |
prms | Dictionary of parameter objects |
param_exists(param_name) | Check if a parameter exists and is enabled |
set_placeholder(name, value) | Register a parameterized query placeholder |
configurables | Dictionary of configurable values set by the application |
The ref() macro
The ref() macro is used to reference other models. Federate models can reference:
- Sources (with
load_to_vdl: trueor DuckDB connection type) - Seeds
- Build models
- Dbview models
- Other federate models
Python federate models
Python federate models define amain() function that receives a ModelArgs object and returns a Polars LazyFrame (or DataFrame).
Example Python model
models/federates/fed_transactions_summary.py
YAML configuration
The YAML configuration file specifies dependencies and other options:models/federates/fed_transactions_summary.yml
Configuration fields
A description of the model for documentation purposes or for use by data consumers (such as AI agents).
List of model names this federate depends on. Optional for SQL models (derived from
ref() calls), but required for Python models.If
true, the SQL model result is materialized as a TABLE in memory. If false, it’s created as a VIEW. This only applies to SQL models. See Eager vs lazy evaluation for details.Column metadata definitions as a list.
Eager vs lazy evaluation
Theeager setting controls how SQL federate models are created in DuckDB:
| Setting | DuckDB Object | Use Case |
|---|---|---|
eager: false (default) | VIEW | Single-use results, saves memory |
eager: true | TABLE | Results referenced multiple times, complex calculations |
- The federate model result is materialized as a TABLE in the temporary in-memory DuckDB database per request
- Subsequent references to this model read from the materialized table
- This prevents redundant computation when the same result is used multiple times
The
eager setting only applies to SQL federate models. Python federate models use polars LazyFrames or DataFrames (depending on what is returned by the model). However, they are registered with DuckDB when referenced by downstream SQL models, or collected as a DataFrame if used as the dataset response.Using placeholders for SQL injection prevention
For user-provided values, use placeholders to prevent SQL injection:models/federates/fed_transactions.sql
$placeholder_name syntax (for DuckDB) is used in the query for parameterized execution.
The placeholder can be set using context variables in pyconfigs/context.py. For instance:
pyconfigs/context.py
Connecting to datasets
Insquirrels.yml, you reference a data model as the model for a dataset. The target model can be any type of data model (source, seed, build, dbview, or federate):
squirrels.yml
Best practices
- Use descriptive names: Prefix federate names with
fed_to distinguish them from other model types. - Use context variables: Define complex logic in
context.pyand use simple context variable references in your SQL/Python models. - Declare dependencies in YAML: Unlike SQL models which auto-detect dependencies via
ref(), Python models require explicitdepends_onin the YAML configuration. It is also recommended to declare dependencies in YAML for SQL models. - Document conditional columns: If a specific column only exists based on parameter selections, use the
conditionfield to document it. - Use placeholders for user input: Always use
set_placeholder()for values that come from user text input to prevent SQL injection. - Mask sensitive data: Use conditional logic based on user fields to mask sensitive columns.
Related pages
- Sources - Configure source tables from external databases if loading to the VDL
- Seeds - Static CSV data files
- Build models - Materialized models in the VDL
- Dbview models - Dynamic models that run on external databases
- Context variables - Set context variables that transform parameter selections into meaningful values at runtime
- ModelArgs - API reference for Python federate model arguments