Getting Started
This page is for data engineers who want to try tablespec without first learning the whole project. You will install the package, write one Universal Metadata Format (UMF) source-table spec, validate it, and compile artifacts that a data pipeline can run or review.
Install
tablespec is distributed via GitHub Pages. The --index-url flag is required.
# Using uv (recommended)
uv add tablespec --index-url https://documentdrivendx.github.io/tablespec/simple/
# Using pip
pip install tablespec --index-url https://documentdrivendx.github.io/tablespec/simple/Add the [spark] extra only if you need PySpark-based profiling, JDBC
discovery, or DataFrame validation:
uv add tablespec[spark] --index-url https://documentdrivendx.github.io/tablespec/simple/Author a UMF table spec
Universal Metadata Format (UMF) is tablespec’s schema contract for a source
table. The canonical UMF editing format is a split directory: one
table.yaml file for table-level metadata plus one file per column under
columns/. Build one from Python:
from pathlib import Path
from tablespec import UMF, UMFLoader
from tablespec.ingestion.constants import PROVENANCE_COLUMNS
umf = UMF.model_validate({
"version": "1.0",
"table_name": "medical_claims",
"canonical_name": "Medical Claims",
"description": "Healthcare claims - source-faithful ingested bronze",
"primary_key": ["claim_id"],
"columns": [
{"name": "claim_id", "data_type": "VARCHAR", "length": 50,
"description": "Unique claim identifier", "nullable": {"MD": False, "MP": False}},
{"name": "member_id", "data_type": "VARCHAR", "length": 20,
"description": "Member identifier", "nullable": {"MD": False, "MP": False}},
{"name": "service_date", "data_type": "DATE",
"description": "Date of service", "nullable": {"MD": False, "MP": True}},
{"name": "billed_amount", "data_type": "DECIMAL", "precision": 12, "scale": 2,
"description": "Amount billed by provider", "nullable": {"MD": True, "MP": True}},
# Provenance columns the ingest pipeline adds to every table.
# `tablespec validate` requires them; JDBC discovery appends them for you.
*(dict(col) for col in PROVENANCE_COLUMNS.values()),
],
})
UMFLoader().save(umf, Path("tables/medical_claims"))This writes:
tables/medical_claims/
├── table.yaml
└── columns/
├── billed_amount.yaml
├── claim_id.yaml
├── member_id.yaml
├── service_date.yaml
└── meta_*.yaml # 8 provenance columnsEach file is small enough for code review. table.yaml names the table and
its primary key:
canonical_name: Medical Claims
description: Healthcare claims - source-faithful ingested bronze
primary_key:
- claim_id
table_name: medical_claims
version: '1.0'columns/claim_id.yaml defines one source column:
column:
data_type: VARCHAR
description: Unique claim identifier
length: 50
name: claim_id
nullable:
MD: false
MP: falseThe MD / MP keys under nullable are context labels for this healthcare
example: Medicaid and Medicare Part D. Other domains can use their own
context labels. See
Universal Metadata Format for the full model.
Validate and inspect
tablespec validate tables/
tablespec info tables/medical_claims/validate checks structure, column naming, expectation compatibility with
Great Expectations, relationship integrity, and pipeline completeness
(including the provenance columns above). It accepts split directories and
JSON files; legacy single-file YAML specs are refused with a pointer to the
migration helper.
Generate artifacts
An artifact is a generated file that downstream tools consume. Each
generate format writes one artifact to stdout so it can be piped:
tablespec generate tables/medical_claims/ -f sql > medical_claims.ddl.sql
tablespec generate tables/medical_claims/ -f pyspark > medical_claims_schema.py
tablespec generate tables/medical_claims/ -f json > medical_claims.schema.json
tablespec generate tables/medical_claims/ -f ingest > medical_claims.ingest.sqlThe ingest format is the raw-to-ingested SQL plan for Databricks/Delta: a
raw landing table DDL, a typed target DDL, and the MERGE transform between
them.
See Compiled artifacts for what each artifact contains.
Emit a dbt project
tablespec emit tables/ out/dbt --backend dbt --dialect databricksThis writes a dbt project to out/dbt: model SQL with declared casts,
enforced contracts, sources, and profiles. Pass --dialect duckdb (the
default) to run it locally, or add --run to execute dbt build through
dbt-duckdb against the emitted project.
Generate a guidebook
tablespec guidebook tables/ -o out/guidebookThe guidebook is a static HTML review site for a directory of UMF specs. It writes one page per table, a table index, column metadata, validation rules, foreign-key consumers, derivation sources, survivorship notes, and a JSON search index. Pages are self-contained: no JavaScript framework, no network dependency, and no server required.
When tables are organized in subfolders, guidebook output keeps those groups as folders. When every UMF sits at the root, output is flat.
Compile from Python
The same artifact generators are available as Python functions. They take a
plain dict (use model_dump) and return the generated SQL, Python source,
JSON Schema, or expectation list:
from pathlib import Path
from tablespec import (
BaselineExpectationGenerator,
UMFLoader,
generate_json_schema,
generate_pyspark_schema,
generate_sql_ddl,
)
umf = UMFLoader().load(Path("tables/medical_claims"))
umf_data = umf.model_dump(mode="json", exclude_none=True)
ddl = generate_sql_ddl(umf_data) # Spark SQL CREATE TABLE (str)
schema_src = generate_pyspark_schema(umf_data) # Python source for a StructType (str)
json_schema = generate_json_schema(umf_data) # JSON Schema (dict)
expectations = BaselineExpectationGenerator().generate_baseline_expectations(umf_data)
print(f"{umf.table_name}: {len(umf.columns)} columns, {len(expectations)} baseline expectations")Legacy single-file YAML specs can still be loaded in Python with
load_umf_from_yaml(path) — file paths only; the CLI does not accept them.
On Databricks
If source tables already exist in a database, you can skip hand-authoring.
Point tablespec at the database over JDBC and it discovers one validated UMF
spec per table: columns and types from INFORMATION_SCHEMA, the reflected
Spark schema, primary and foreign keys, and the required provenance columns.
Credentials are never inlined; the spec carries only a password_secret_ref
naming a secret in the runtime’s secret store.
The Northwind demo notebooks run this database-discovery path end to end on a Databricks cluster: provision SQL Server on the driver node, discover the whole database, validate every spec, and land typed tables with staged validation reports that work on classic clusters and serverless.