Skip to content

Module 2 — Your first schema package

You need a new table. The old way: write a CREATE TABLE, remember to guard it so it doesn’t blow up if it already exists, slot it into the migration chain, and hope nobody’s run it somewhere you forgot. Let’s do it the declarative way instead — describe the table you want, quench it, done.

In SchemaSmith, a table is just a file. Remember the package you kindled in Module 1? It’s got a Main template and no tables yet. Let’s lay the first one on the anvil. Create Templates/Main/Tables/dbo.Widget.json:

{
"Schema": "dbo",
"Name": "Widget",
"Columns": [
{ "Name": "WidgetId", "DataType": "BIGINT" },
{ "Name": "Name", "DataType": "NVARCHAR(100)" },
{ "Name": "Quantity", "DataType": "INT", "Nullable": true }
],
"Indexes": [
{ "Name": "PK_Widget", "PrimaryKey": true, "Clustered": true, "IndexColumns": "WidgetId" }
]
}

That’s the whole thing. Three columns, a primary key. No CREATE TABLE, no IF NOT EXISTS, no ordering to worry about — you’re describing the destination, not the steps. PostgreSQL and MySQL use the same shape with small dialect tweaks (the lab has all three). For the full list of fields a table file accepts — computed columns, foreign keys, check constraints, and the rest — the schema-packages reference is your map.

From your engine’s lab folder:

Terminal window
schemaquench --ConfigFile:deploy.settings.json
[localhost,11433].[learn] Adding new table [dbo].[Widget]
[localhost,11433].[learn] Creating constraint [dbo].[Widget].[PK_Widget]
[localhost,11433].[learn] Successfully Quenched
Completed quench of LearnConnect

SchemaSmith read your declared state, saw the learn database had no Widget, and created it — table and primary key in one pass. (PostgreSQL says Create new table public.Widget; MySQL says Create table `Widget` .) Every flag and setting on that command is in the SchemaQuench reference.

Same command, no edits:

Terminal window
schemaquench --ConfigFile:deploy.settings.json

This time there’s no Adding new table line. Nothing happens. The declared state already matches the database, so the difference is zero and SchemaSmith applies zero. Run it ten more times — same result. That’s the quench doing exactly what it should: shaping the metal only when the metal needs shaping.

That’s the difference from a migration script. A CREATE TABLE script you run twice is an error you have to guard against. A declared table you quench twice is just… done, twice.

Check yourself: After SchemaQuench creates your table, what happens if you run the exact same command again?

Nothing changes — the declared state already matches the database, so there’s no difference to apply. The deployment is idempotent.


One file, one command, a table on the anvil — and a re-run that knows to leave well enough alone. You’ve done the core SchemaSmith loop now: declare, quench, trust.

Stuck on a column type or a constraint that won’t take the shape you want? Email me at forgebarrett@schemasmith.com — I read every one.

Next up: Module 3 — Change it and redeploy. We’ll evolve this table and let SchemaSmith work out the exact change — with a preview before it touches a thing.

Until then, may your first table stand square and your re-runs stay quiet.

— Forge