The on-disk representation of a database schema definition. Every tool in the suite reads, writes, or modifies schema packages.
By the SchemaSmith Team · Last reviewed
A schema package is your database's source of truth — the complete, version-controlled definition of what your databases should look like.
A schema package is the on-disk artifact that every SchemaSmith tool produces or consumes.
It is a folder — or a .zip archive of that folder — holding the product and
template configuration, the table definitions, the SQL scripts, and the JSON Schemas that
validate every file in the package. One package, one deployable unit, one source of truth.
The package's contents are described elsewhere in the documentation: see Products and templates for the JSON configuration files at the package's core, Defining tables for the table JSON format, and Data delivery alongside Conditional application for the declarative data and deployment controls table files can carry. This page focuses on the package as a container: where files live, how the folder tree is laid out, how ZIP distribution works, and how filesystem-illegal object names get encoded onto disk.
A schema package is a predictable directory tree. Every tool in the SchemaSmith toolset
discovers what it needs by convention — Product.json at the root,
Templates/ one level down, platform-specific script folders inside each
template — so you never have to configure paths or point a tool at individual files.
Marker files and generated artifacts sit alongside the files you author, and the whole
layout maps cleanly onto source control.
MyProduct/
Product.json Product configuration (required)
.json-schemas/ JSON Schema files for IDE validation (generated)
products.<platform>.schema <platform> = sqlserver, postgresql, mysql, or mariadb
templates.<platform>.schema
tables.<platform>.schema
indexedviews.sqlserver.schema SQL Server packages
materializedviews.postgresql.schema PostgreSQL packages
sequences.postgresql.schema PostgreSQL packages
enumtypes.postgresql.schema PostgreSQL packages
domaintypes.postgresql.schema PostgreSQL packages
events.mysql.schema MySQL packages
events.mariadb.schema MariaDB packages
.community Marker file (generated by SchemaTongs)
Before Product/ SQL scripts run before all templates
After Product/ SQL scripts run after all templates
Templates/
TemplateName/
Template.json Template configuration (required)
Tables/ Table definition JSON files (all platforms)
public.customer.json
sales.order.json
Indexed Views/ Indexed view definitions (SQL Server only)
dbo.vw_OrderSummary.json
Materialized Views/ Materialized view definitions (PostgreSQL only)
public.mv_active_orders.json
data/ DataDelivery content files (.tabledata)
public.customer.tabledata
<platform default folders> See Default Folders on Products and Templates
<custom folders> Anything you declared in ScriptFolders
Table JSON files are named schema.tablename.json (e.g.,
dbo.Customer.json, public.order_lines.json). The schema segment mirrors the
table's own Schema property, so it is omitted whenever the table carries no schema — on
MySQL and MariaDB (no per-table schema), and in schema templates, where the schema is the iteration
variable. See File naming below. If a table or schema name contains
filesystem-illegal characters, the encoded form is used in the filename — see
Filesystem-Illegal Character Encoding.
SQL script files can be organized into subdirectories within any script folder. All
.sql files are discovered recursively and sorted alphabetically by full path.
How you name table JSON files depends on your platform, the template kind — regular template or schema template — whether the table declares its Schema, and whether it carries conditional variants.
Regular templates use schema-prefixed filenames. The prefix mirrors the
table's Schema property, so a file listing tells you at a glance which schema each
table belongs to: dbo.Customers.json, Sales.Orders.json,
public.order_lines.json. A table that omits Schema falls back to the
platform default — dbo on SQL Server, public on PostgreSQL.
Because the filename mirrors content, a table that omits Schema has no prefix to mirror, and its
canonical name is the bare order_lines.json. Both forms are correct so long as the
filename and the content agree: declare Schema: "public" and name the file
public.order_lines.json (what the shipped PostgreSQL demos do), or omit both. On
extraction SchemaTongs writes the omitted form for a PostgreSQL table in public, and
keeps the prefix for a named schema; a SQL Server table keeps its schema, dbo included.
MySQL and MariaDB have no per-table schema, so their packages use unqualified filenames throughout,
whatever the template kind.
Schema templates use unqualified filenames. The schema is the iteration
variable — SchemaQuench resolves {{SchemaName}} at runtime for every iteration,
so Customers.json deploys into acme.Customers for the
acme tenant, globex.Customers for the globex tenant,
and so on. Filenames with a schema prefix (e.g., dbo.Customers.json) inside a
schema template's Tables/ folder are rejected by the engine at load time.
Cross-schema tables. A schema template cannot own a table in a specific named
schema. Both routes to it are rejected at load time: a schema-prefixed filename in its
Tables/ folder (above), and a literal Schema value on the table itself — a schema
template requires Schema to be omitted, empty, or the literal {{SchemaName}} token,
because the table lives in {{SchemaName}} by construction. Put shared, fixed-schema
tables such as dbo.SharedConfig in the accompanying regular template that runs first in
TemplateOrder.
The accompanying Shared regular template (if present) follows the regular-template
convention above: dbo.Tenants.json on SQL Server, countries.json for a
PostgreSQL public table, reference.countries.json for one in a named schema. Its
filenames are unchanged by the presence of a schema template in the same product.
Conditional variants. A table
carrying conditional variants
takes an optional VariantName segment after the table name —
dbo.Customers.Premium.json sitting beside dbo.Customers.json
— so a table's variants sort together in source control and in a file listing.
SchemaTongs writes each table file under the canonical name for your platform and template kind, but that
name is a convention rather than a contract. A table's identity lives in its file content, so a
file you renamed by hand still deploys, and re-extraction refreshes it in place instead of
duplicating it. Running SchemaQuench with --Validate reports any drift from the
canonical form as an SS-FILE-NAME-003 warning naming the expected filename.
For the canonical form on your platform, with its exact schema-segment rule, see the SchemaTongs reference: SQL Server, PostgreSQL, MySQL, or MariaDB.
For a worked layout showing these conventions side by side, see Multi-Tenant Deployments.
Your IDE helps you write correct JSON without being configured to. The
.json-schemas/ directory at the package root contains JSON Schema definition
files generated automatically by SchemaTongs on the fly from the live C#
domain types — no embedded files, no shipped artifacts, just a snapshot of the engine's
exact current shape.
Every package JSON opens with a $schema key naming its schema by relative path,
which is what makes an editor pick it up with no json.schemas entry or equivalent.
SchemaTongs writes it on extraction, and --WriteSchemasOnly adds it to a package
extracted before v2.7.0. A package carrying the key will not load on SchemaSmith v2.6.0 or
earlier, which is worth knowing if the same package is deployed by more than one version during
an upgrade.
Each file carries a platform infix matching the package's platform —
<platform> is sqlserver, postgresql, mysql, or
mariadb:
| File | Validates |
|---|---|
products.<platform>.schema |
Product.json |
templates.<platform>.schema |
Template.json |
tables.<platform>.schema |
Table JSON files (Tables/*.json) |
indexedviews.sqlserver.schema |
Indexed view JSON files (SQL Server packages) |
materializedviews.postgresql.schema |
Materialized view JSON files (PostgreSQL packages) |
sequences.postgresql.schema |
Sequence JSON files (PostgreSQL packages) |
enumtypes.postgresql.schema |
Enum type JSON files (PostgreSQL packages) |
domaintypes.postgresql.schema |
Domain type JSON files (PostgreSQL packages) |
events.mysql.schema |
Scheduled event JSON files (MySQL packages) |
events.mariadb.schema |
Scheduled event JSON files (MariaDB packages) |
Not every setting means something on every engine, and a generated schema reflects that:
most inapplicable settings are simply absent —
MemoryOptimized is a SQL Server table property, so it appears in a SQL Server
package's table schema and in no other, and your editor stops offering it elsewhere. The
table-level drop-control overrides follow the same rule:
DropExcludeConstraintsRemovedFromProduct appears only in a PostgreSQL package's
table schema and DropStatisticsRemovedFromProduct only in SQL Server and
PostgreSQL ones, each with a note naming its engines. Set a setting its engine's schema does
not offer and --Validate reports SS-JSON-001, an Error-severity
finding that exits 2 — the package still loads and every other check still
runs, so it is a lint rather than a load failure.
Because the schemas are regenerated every time SchemaTongs writes a package, they always
match the current engine. If you've hand-edited any of them to add a custom validation
fragment under Extensions, that fragment is preserved through regeneration —
see Custom Properties: JSON Schema Validation.
SchemaQuench can consume schema packages as ZIP archives. When the
SchemaPackagePath configuration value points to a .zip file,
SchemaQuench reads the package directly from the archive without extracting it to disk
first.
Requirements:
This is useful for deployment pipelines where the schema package is built as a single artifact.
Object names can contain characters that are illegal in file paths on Windows, macOS, or Linux. SchemaTongs uses a percent-encoding scheme — the same mechanism RFC 3986 §2.1 defines for URIs — to safely map these names to filenames.
| Character | Encoded As |
|---|---|
\ | %5C |
/ | %2F |
: | %3A |
* | %2A |
? | %3F |
" | %22 |
< | %3C |
> | %3E |
| | %7C |
% | %25 |
Additional rules:
%20 for space, %2E for dot) because many filesystems strip or reject them at the start of filenames.SchemaQuench decodes these filenames transparently when reading definitions. You generally don't need to worry about encoding unless you're creating JSON files by hand for tables with unusual names.
Build a schema package folder structure from scratch, add your table definitions, and run them through SchemaQuench.
Build a packageFree schema-as-code for SQL Server, PostgreSQL, MySQL, and MariaDB.
The source is on GitHub for anyone to read.
Get Started on GitHub