Ignition 8.3+ Gateway Module
SchemaForge compiles a code-first schemaforge DSL into a structural diff against your live datasource, classifies every change as safe or destructive, and applies it through Liquibase — DBMS-agnostic by construction, and never automatic.
Why It Exists
Most Ignition projects track schema changes as ad hoc SQL scripts, if they're tracked at all — with no diff, no classification, and no record of what's actually pending against which environment.
Without SchemaForge
With SchemaForge
How It Works
Write the DSL
A schema or seed resource is edited as plain schemaforge DSL text in the Designer, compiled to a Model IR. A resource that doesn't compile doesn't save.
Resolve and diff
On save or Gateway restart, __environment__ tags resolve to real datasources and the Model IR is diffed against the last applied snapshot.
Compile the changeset
Every change compiles to a Liquibase changeset and is classified safe (additive) or destructive (drops, type changes) — no in-between.
Operator reviews and applies
The Pending Changes page lists outstanding changes per resource. Apply safe changes, or explicitly confirm the destructive ones.
Module Architecture
Built with the io.ia.sdk.modl Gradle plugin as an installable Ignition 8.3 module.
common
DSL parser/compiler, Model IR, diff engine, JSON (de)serialization, reverse-engineering DSL writer, Designer↔Gateway RPC interface.
designer
Resource workspaces/editors for Schemas and Seeds, plus the reverse-engineering wizard.
gateway
Resource lifecycle observation, Liquibase changeset compilation and execution, seed upsert execution, database introspection, environment→datasource settings, REST routes.
web-ui
React/TypeScript Gateway pages — settings, Pending Changes, Seeds — built with Webpack into a SystemJS module bundled into the Gateway jar.
Two Resource Types
Both compile to a plain-Java Model IR in the Designer, so the Gateway never has to parse DSL itself — it works from the compiled IR stored alongside the resource.
Schema resource
Seed resource
Reverse Engineering
"Reverse Engineer from Database..." on the Schemas folder introspects an existing datasource and generates a real schema-model resource — through the same creation flow, and the same compile-or-it-doesn't-save gate, as anything hand-written.
Choose a datasource
Launch the wizard from the Schemas folder in the Designer and point it at an existing Ignition datasource connection.
Read DatabaseMetaData
Columns, types, primary/foreign keys, and indexes are read directly via JDBC DatabaseMetaData.
Write the DSL
The introspected structure is written out as schemaforge DSL source, not just an opaque IR blob.
Same save gate as hand-written
The generated resource must compile to save — no special-cased path for reverse-engineered schemas.
Gateway Web UI
A React/TypeScript, SystemJS-mounted Gateway page, reusing Ignition's own pooled JDBC connections.
Environment → Datasource
Maps each __environment__ tag used in resources to a real Ignition datasource connection, resolved on every save and restart.
Pending Changes
Every resource's outstanding safe and destructive changes, listed separately, with "apply safe changes" and a confirm-gated "apply including destructive" action.
Seeds
Every enabled seed and its resolved datasource(s), run on demand — idempotent upserts, safe against a datasource that already has rows.
Not Built Yet
Live-verified against real MSSQL and Postgres datasources — with known gaps, stated plainly rather than papered over.
COLUMN_DEF SQL text isn't parsed, so defaults are added by hand after generating.Building
Build the module
Produces build/SchemaForge.unsigned.modl always, plus a signed build/SchemaForge.modl if signing credentials are configured.
./gradlew buildSign locally (optional)
A self-signed keypair works for dev/internal use — the Gateway prompts to trust the certificate once, rather than requiring -Dignition.allowunsignedmodules=true on every reinstall. Signing properties live in ~/.gradle/gradle.properties, never in the repo.
Deploy to a dev Gateway
deployModl pushes to localhost:8088 by default — override tasks.deployModl.hostGateway or pass -PhostGateway=... for a different target.
./gradlew deployModlRestart required
Ignition 8.3 does not hot-reload modules — every change means reinstalling the .modl and restarting the Gateway, and reconnecting the Designer for designer-scope changes.
Get in touch
Happy to walk through the DSL, the diff/classification engine, or the reverse-engineering wizard for a specific schema.