Schema Evolution
Schema changes in Causet fall into two categories: safe changes you can deploy with no ceremony, and breaking changes that require a migration strategy.
Safe changes (additive, deploy freely)
These changes can be deployed without a rebuild or data migration:
Events
- Add an optional payload field
- Add a new event type
- Add a new action
- Add a new projection
Projections
- Add a new column (
fields:+derive:) - Add a new index
- Add a new event type to
source_events - Add a new aggregate
- Add a new mutation op for an existing event
Queries
- Add a new query
- Add a new optional input field
- Add a new WHERE clause (restricts results further)
- Increase limit
Note: Adding a column to a projection requires a redeploy to apply the DDL. The column will be NULL for existing rows until events are replayed.
Breaking changes (require migration strategy)
These changes require care:
| Change | Risk | Strategy |
|---|---|---|
| Remove event payload field | Breaks projections, rules that reference it | Deprecation period: deploy new IR without references first |
| Rename event payload field | Breaks all references | Version the event (V2 pattern) |
| Change payload field type | Type mismatch in projections | Version the event |
| Change projection primary key | Existing rows become orphaned | Rebuild (truncate + replay) |
| Remove a projection column | Queries referencing it break | Remove query references first, then column |
| Change query input type | Client breakage | Version the query |
| Rename event type | Breaks all source_events references | Version the event |
V2 event pattern
When an event’s payload shape needs to change:
-
Introduce a new event type with V2 naming:
events: TICKET_PURCHASED: # old — keep for backward compatibility ... TICKET_PURCHASED_V2: # new — enhanced payload state: ticket payload: ticket_id: string user_id: string show_id: string seat_number: string # new field price_cents: int # new field -
Emit both from actions during transition:
side_effects: rules: - name: emit_purchase then: - op: emit event_type: TICKET_PURCHASED_V2 payload: ticket_id: intent.ticket_id user_id: intent.user_id show_id: intent.show_id seat_number: intent.seat_number price_cents: intent.price_cents -
Update projections to source from the new event type.
-
Rebuild affected projections to backfill historical V2 events.
-
After full migration: deprecate and remove
TICKET_PURCHASED.
Column removal
Projection columns are not automatically removed on deploy (IR-driven DDL is additive only).
To remove a column:
- Remove all query references to the column.
- Remove the column from the projection
fields:andderive:. - Deploy new IR.
- Manually run DDL:
ALTER TABLE ... DROP COLUMN ...
Warning: Remove query references before dropping the column. Dropping a column with active queries causes query failures.
Primary key changes
Changing a projection’s primary key is a destructive operation.
Procedure:
- Create a new projection with the correct primary key and a different name.
- Replay events to build the new projection.
- Update queries to reference the new projection.
- Deploy query changes.
- Remove the old projection from DSL.
- Drop the old table manually.
IR versioning
Every compile produces a new IR version (hash). Active version per fork is managed by causet-saas-cloud.
- Rolling back IR: deploy the previous release in the control plane.
- Rollback safety: projection DDL is additive — rolling back IR does not drop columns.
- Stale IR: projection worker and query service may cache the IR (Redis TTL). After deploying, wait for cache refresh or restart services.
Compiler validation
The compiler validates cross-references at compile time:
- Events referenced in
source_eventsmust exist in theevents:section - Fields referenced in
derive:must exist in the event payload schema - Fields referenced in query
where:must exist in the projectionfields:
If you rename an event or remove a payload field, the compiler will catch all references and report errors before the release is deployed.
Run the compiler in CI on every PR to catch schema evolution issues early.