Docs

Templates

The SQL that maintains your history and bridge layers is generated from templates your target connector owns. They are deterministic, dialect-native, and readable.

Overview  

Amfelt does not hand you a black box that emits SQL. The SQL that maintains your history and defines your bridge layers is rendered from templates, and a template is a file, one you can read to find out exactly what a run will do before it does it.

Why Templates Rather Than a Query Builder  

A query builder abstracts over dialects, and abstraction over SQL dialects costs you the parts that differ, which are usually the parts worth having. PostgreSQL’s ON CONFLICT, DuckDB’s INSERT OR IGNORE, and BigQuery’s MERGE solve the same problem three ways, and a builder that covers all three either exposes the difference anyway or picks the common denominator.

Templates take the other side of that trade. Each target’s templates are written for that target’s dialect, so what lands in your data platform looks like SQL a competent engineer on that platform would have written.

Templates Belong to the Connector  

The templates for a dialect live inside that target’s connector, compiled into it rather than into the agent. The agent orchestrates and holds none of the SQL that builds your layers.

The practical consequence is release independence. Fixing how history is maintained on one data platform means releasing that connector, not the agent, and not every other connector alongside it. A new target ships its own SQL with it and needs no change to anything already running.

The Same Inputs Produce the Same SQL  

Rendering is deterministic: the same contract and the same template produce the same SQL every time, apart from the run’s ID and start time, which are stamped into each record’s audit properties. Nothing is generated at run time by a model, and nothing depends on which agent picked the run up.

That property is what makes the rest of the platform’s guarantees mean anything. A run you can reproduce is one you can audit, roll back to, and compare against. None of that survives a generator whose output drifts between runs.

What Gets Rendered  

The DML that maintains the history layer, for the mode you chose, and the bridge views over it (see Write Modes and History ). The DDL for each object is generated by the connector from the contract’s resolved types (see Type Resolution ), and staging records are written through the data platform’s bulk-load interface.

That page is also worth reading if you have seen the word template used elsewhere on this site to mean the historization strategy itself. The two are related but distinct: historyMode is the choice you make, and templates are how that choice is turned into SQL for your particular data platform.

Customizing Them  

Templates are structured so that a project-specific override can be supplied without changing anything else. Put a replacement in templates/<plugin>/<name>.sql beside the project file, and amfelt template eject <plugin> <template> copies the shipped template there as a starting point; it never overwrites an override you have already edited. A target refuses an override for a template it does not list as overridable.

Next  


Last updated on October 31, 2026