Extension Points
NLT provides two Protocol-based extension points that let you integrate the engine with your own data sources and template storage. Both are optional -- NLT works out of the box with just the data you pass to the constructor.
EventStore Protocol
When to Implement
Implement EventStore when you need to look up events that are not available in the additional_events dictionary at render time. This is useful when:
- Your event history is large and pre-loading all events would be impractical
- You want to fetch events lazily from a database or API
- The template references event types that were not known at flow trigger time
Protocol Definition
The method should return an event dict with an attributes key, or None if no matching event exists.
The EventStore protocol is currently reserved for future async integration. The synchronous rendering pipeline does not invoke async methods. The protocol is defined for forward compatibility -- implement it now so your integration is ready when async rendering is available.
Example: Database EventStore
TemplateLoader Protocol
When to Implement
Implement TemplateLoader to enable {extends} template inheritance. The loader is responsible for finding and returning the raw template string for a given template name.
Without a TemplateLoader, {extends} declarations are silently ignored and the child template is rendered as-is.
Protocol Definition
Returns the raw template string, or None if the template is not found.
Example: Filesystem Loader
Example: Database Loader
For production use, wrap your TemplateLoader with an in-memory cache. Base templates rarely change, and caching avoids repeated database or filesystem lookups during high-volume rendering.
Integration Patterns
Minimal Integration
The simplest integration passes all data inline with no protocols:
Full Integration
A production integration typically provides both protocols:
One Renderer Per Email
Create a new NLTRenderer instance for each email you render. The renderer tracks suppression state and loop/macro context internally, so reusing an instance across multiple renders can produce incorrect results.
Next Steps
- API Reference: Renderer -- full method signatures for NLTRenderer, EventStore, and TemplateLoader
- Jinja2 Migration -- convert existing Jinja2 templates to NLT