Versioning & lifecycle
Templates carry an explicit lifecycle so changes can be staged, reviewed, and rolled out without disturbing emails that are already in flight.
Status
| Status | Meaning |
|---|---|
| Draft | The template is being authored. Safe to edit freely. |
| Published | The template is in active use. Changes should be deliberate and tested. |
Newly created templates start as Draft. Promotion to Published is an
explicit action — set status: 1 when saving.
Versions as separate rows
Every version of a template is stored as its own row. The combination of
(templateKey, version) is unique: editing a published template never
overwrites the previous version, and rolling forward never loses history.
- A brand-new template is created at version
1(statusDraft). - A new version is produced through the dedicated "create version" endpoint,
which copies the source row and inserts it at
version = max(version) + 1with statusDraft. - At most one Draft can exist per template key at any given time — creating another is rejected until the existing draft is published or deleted.
This separation means you can keep editing the next draft of a template while the currently-published version continues to be the one the system sends.
Lifecycle of a change
- Identify the row to evolve (typically the currently-published version).
- Call the "create version" endpoint with that row's id. The server clones it into a new Draft at the next version number.
- Edit the Draft freely — name, description, MJML, context binding, status.
templateKeyandversionthemselves are immutable on a row. - Preview against representative sample data, in every supported locale.
- Flip the Draft to
Publishedvia the edit endpoint. The previous published version stays in the table as history.
Editing rules
templateKeyandversionare fixed for the life of a row.- Everything else (
templateContextKey,name,description,mjmlSource,status) is mutable through the edit endpoint, regardless of whether the row is Draft or Published. - Content changes to a Published row are allowed but should be reserved for fixes you would not consider "a new version" (a typo in copy, a colour tweak). Anything bigger should go through a new version.
How sends pick a version
Real transactional sends are dispatched from backend code, which resolves
a templateKey to the latest Published version of that key and renders
that row. Editing a Draft therefore never affects live sends; the moment a
draft is flipped to Published, its (templateKey, version) becomes the
new latest-published row and the next send picks it up.
The HTTP send endpoint exposed by the API takes a row id directly and sends that exact row regardless of status. It exists so authors can test drafts against real inboxes before publishing them — it is not the production send path.
Deletion
Deleting is a soft-delete and supports two modes:
- Single version — supply
templateKeyand theversionto remove. - All versions — supply
templateKeyand setdeleteAllVersions = true.
Exactly one of the two selectors must be provided.
Because rows are soft-deleted, the underlying unique constraint on
(templateKey, version) still holds, so the deleted version number cannot
be re-used without first restoring or hard-deleting the row at the database
level.
Editing fragments
Fragments are not versioned individually. Editing a fragment immediately affects every template that references it on the next render.
This is intentional: shared building blocks like "the brand button" or "the standard footer" should change everywhere at once. Templates that need isolation from upstream fragment changes should be built without the shared fragment.
Why versions matter
- History. Every published version is preserved as a row, so older emails can always be traced back to the exact template that produced them.
- Cache invalidation. Rendered HTML is cached by template id, version and content hash. A new version row gets a fresh cache slot automatically.
- Predictable rollouts. Sends always pick the latest Published version for a key — promoting a draft is the single action that flips traffic to the new design.