High-fidelity synthetic data generation for Snowflake
Project description
sf-synth
High-fidelity synthetic data generation for Snowflake.
A Snowpark-first Python library and CLI that generates realistic synthetic data inside Snowflake using auto-discovered schema, distribution statistics, Faker-based rules, and a DAG-driven referential-integrity engine. All generation runs server-side, so PII never leaves the account.
Features
- Snowpark-first execution: Data is generated entirely within Snowflake using Snowpark. No data egress required.
- Auto-discovery: Automatically detects tables, columns, types, constraints (PK, FK, UNIQUE, NOT NULL) from
INFORMATION_SCHEMA. - Referential integrity: DAG-based generation ensures parent tables are populated before children. FK values are sampled from actual parent keys.
- Self-referential tables: Handles self-referential FKs (e.g.,
employees.manager_id → employees.id) via two-pass generation. - Multi-schema support: Reference tables across different schemas within the same database.
- Distribution-preserving: Sample from real column statistics (
APPROX_TOP_K,APPROX_PERCENTILE,HLL) to preserve data distributions without exposing PII. - Skewed FK distributions: Zipf-weighted FK sampling for realistic skew (e.g., 80% of orders belong to 20% of customers).
- Correlated columns: Group
fakercolumns socity/state/countryare drawn from the same Faker profile and stay semantically consistent within a row. - Temporal ordering: Column-level
afterconstraints to enforce realistic timelines (updated_atalways aftercreated_at). - Semi-structured data: First-class generators for VARIANT/ARRAY/OBJECT, plus a
json_templatemini-DSL for nested payloads. - Computed columns: Use a raw SQL
expressiongenerator for derived fields likeFULL_NAME = FIRST_NAME || ' ' || LAST_NAME. - Conditional generation:
condition+else_valueto drive a column's value from another column. - Write modes:
replace/append/upsert/fill_toper table or via--mode. - Parallel generation: Independent tables in the DAG run concurrently with
--parallel N. - Validate & preview:
sf-synth validatechecks the config against live DDL;sf-synth previewshows sample rows before any writes. - Run reports:
--reportand--profileproduce a markdown summary with row counts, sample rows, and per-column distinct/null/min/max. - Semantic inference: Auto-infers generators from column names (e.g.,
email,phone,created_at). - Deterministic output: Seed-based, hash-driven FK sampling produces fully reproducible runs.
- YAML configuration: Simple, validated config with Pydantic.
Installation
pip install sf-synth
Or install from source:
git clone https://github.com/apareek/snowflake-synthesizer.git
cd snowflake-synthesizer
pip install -e ".[dev]"
Quick Start
1. Discover your schema
Generate a starter config by discovering your existing Snowflake schema:
sf-synth discover MY_DATABASE --output config.yaml
2. Edit the config
Customize row counts, add generators, and define relationships:
defaults:
seed: 42
database: MY_DATABASE
schema: PUBLIC
tables:
- name: CUSTOMERS
rows: 10000
columns:
EMAIL:
generator: faker
provider: email
unique: true
MEMBERSHIP:
generator: choice
values: [Gold, Silver, Bronze]
weights: [0.1, 0.3, 0.6]
- name: ORDERS
rows: 50000
relationships:
- column: CUSTOMER_ID
references: CUSTOMERS.ID
skew: zipf
3. Preview the plan
See the generation order and dependencies without executing:
sf-synth plan config.yaml
4. Validate the config
Catch type mismatches and FK problems before any data is written:
sf-synth validate config.yaml --connection my_conn
5. Preview a few rows
Generate a tiny sample (default 10 rows per table) without writing anything:
sf-synth preview config.yaml --rows 5
6. Generate data
sf-synth generate config.yaml \
--mode replace \
--parallel 4 \
--report run_report.md \
--profile
Useful flags:
--mode replace|append|upsert|fill_to— override per-table write mode.--truncate/--no-truncate— force truncate-before-insert behavior.--parallel N— generate independent tables in parallel.--report PATH— write a markdown summary of the run.--profile— include per-column distinct/null/min/max in the report.--seed N— override the seed for reproducibility.--verbose/--quiet— control log noise.
7. Clean up
Remove temporary tables created during generation:
sf-synth clean config.yaml
Configuration Reference
Defaults
defaults:
seed: 42 # Random seed for reproducibility
locale: en_US # Faker locale
database: MY_DB # Default database
schema: PUBLIC # Default schema
null_ratio: 0.0 # Default null ratio for all columns
Generator Types
| Generator | Description | Required Parameters |
|---|---|---|
seq |
Sequential integers | start, step |
uniform |
Uniform random numbers | min_value, max_value |
choice |
Random selection from list | values, weights (optional) |
range |
Values in numeric/date range | min_value, max_value |
faker |
Faker provider | provider, locale (optional) |
distribution |
Sample from source column stats | source (FQN: DB.SCHEMA.TABLE.COL) |
regex |
Pattern-based strings via exrex UDF |
pattern |
expression |
Raw SQL expression for computed columns | sql |
json_template |
{{...}} template compiled to TRY_PARSE_JSON |
template |
array |
ARRAY_CONSTRUCT(...) of element-generator outputs |
element_generator, length |
object |
OBJECT_CONSTRUCT(...) from a fields mapping |
fields |
Cross-column features
| Field | Description |
|---|---|
correlation_group |
Multiple faker columns in the same group share a single Faker profile per row (consistent city/state/country). |
after |
This date/timestamp column is generated as DATEADD(unit, offset, <other_col>). Tunable via after_offset_unit/after_offset_min/after_offset_max. |
condition / else_value |
Wrap the generator in IFF(<condition>, <generated>, <else_value>). |
Write modes
Per-table (write_mode:) or globally via --mode:
| Mode | Behavior |
|---|---|
replace |
Truncate target then insert (default). |
append |
Insert without truncating. |
upsert |
MERGE on upsert_keys — update existing rows and insert new ones. |
fill_to |
Generate only enough rows to reach rows: total (no-op if already there). |
Faker Providers
Common providers: email, name, first_name, last_name, phone_number, address, city, state, zipcode, country, company, job, date, date_time, uuid4, url, ipv4, ssn, credit_card_number.
Relationships
relationships:
- column: CUSTOMER_ID # FK column in this table
references: CUSTOMERS.ID # Parent table.column
null_ratio: 0.05 # 5% null FKs
skew: zipf # Distribution: uniform or zipf
skew_param: 1.5 # Zipf exponent (higher = more skewed)
Python API
from sf_synth import SynthConfig, SynthEngine, discover_schema
from sf_synth.backend import SnowparkBackend
# Connect to Snowflake
backend = SnowparkBackend(connection_name="my_connection")
backend.connect()
# Discover schema
schema = backend.discover_schema("MY_DATABASE")
# Load config
from sf_synth.config import load_config
config = load_config("config.yaml")
# Generate
engine = SynthEngine(backend.session, config, schema_model=schema)
result = engine.generate()
print(f"Generated {result.total_rows} rows in {result.total_elapsed_seconds:.2f}s")
# Cleanup
engine.cleanup()
backend.disconnect()
Examples
The examples/ directory contains ready-to-use configurations:
| Example | Description |
|---|---|
ecommerce.yaml |
E-commerce schema with customers, products, orders, and reviews. Demonstrates FK relationships, Zipf-skewed distributions, and various generators. |
selfref_employees.yaml |
HR schema with self-referential manager_id FK. Shows how sf-synth handles circular references via two-pass generation. |
multi_schema.yaml |
Enterprise schema spanning CORE, HR, SALES, and FINANCE schemas. Demonstrates cross-schema FK relationships within a single database. |
Architecture
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ CLI │────▶│ Config │────▶│ Discovery │
│ (Typer) │ │ (Pydantic) │ │ (INFO_SCH) │
└─────────────┘ └──────────────┘ └─────────────┘
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ DAG Builder│────▶│ Schema │
│ (networkx) │ │ Model │
└─────────────┘ └─────────────┘
│
▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Stats │────▶│ Engine │────▶│ RI Manager │
│ Sampler │ │ (Snowpark) │ │ (Parent Keys│
│ (APPROX_*) │ └─────────────┘ └─────────────┘
└─────────────┘ │
▼
┌─────────────┐
│ Snowflake │
│ Tables │
└─────────────┘
Connection Configuration
sf-synth uses standard Snowflake connection methods:
- Named connection (recommended):
~/.snowflake/connections.toml - Environment variables:
SNOWFLAKE_ACCOUNT,SNOWFLAKE_USER, etc. - CLI parameters:
--connection,--account, etc.
Example ~/.snowflake/connections.toml:
[my_connection]
account = "myaccount"
user = "myuser"
authenticator = "externalbrowser"
database = "MY_DB"
schema = "PUBLIC"
warehouse = "COMPUTE_WH"
Performance Notes
- SQL-first generators (seq, uniform, choice, range) are fast and scale to billions of rows.
- Faker UDFs are slower due to Python UDF overhead. Use them only when SQL alternatives don't exist.
- Distribution sampling requires one-time stats queries per column but generates data efficiently.
- For very large tables (>100M rows), consider chunked generation or Snowflake-native
GENERATOR()patterns.
Development
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest tests/unit/
# Run integration tests (requires Snowflake credentials)
SF_SYNTH_INTEGRATION_TESTS=1 pytest tests/integration/
# Lint
ruff check src/ tests/
# Type check
mypy src/
License
MIT License. See LICENSE for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sf_synth-0.4.0.tar.gz.
File metadata
- Download URL: sf_synth-0.4.0.tar.gz
- Upload date:
- Size: 67.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6c17b323b3898b4fb0940e118890dcf27a69590c0869c83efe36360c4be95cbe
|
|
| MD5 |
1c659860a3516a44fa57effe2295834c
|
|
| BLAKE2b-256 |
7ed71fb5437a8cbd99f493a5f2dcb2e669f22a0ea30780333ddb4b0756142fff
|
Provenance
The following attestation bundles were made for sf_synth-0.4.0.tar.gz:
Publisher:
publish.yml on aypareek/snowflake-synthesizer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sf_synth-0.4.0.tar.gz -
Subject digest:
6c17b323b3898b4fb0940e118890dcf27a69590c0869c83efe36360c4be95cbe - Sigstore transparency entry: 1493870877
- Sigstore integration time:
-
Permalink:
aypareek/snowflake-synthesizer@e47bbb96fbceacbbe1a34a925ae1a7cfa2bec51b -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/aypareek
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e47bbb96fbceacbbe1a34a925ae1a7cfa2bec51b -
Trigger Event:
push
-
Statement type:
File details
Details for the file sf_synth-0.4.0-py3-none-any.whl.
File metadata
- Download URL: sf_synth-0.4.0-py3-none-any.whl
- Upload date:
- Size: 62.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f187fe01f62d07a624b7f9025aa49b6585b6b8227f10f5a5425eb43994329b0d
|
|
| MD5 |
28ed6f2050632d08be35774c09f312a1
|
|
| BLAKE2b-256 |
4a9e9a3b4a72b148e32b449b6e065c7f0e1c398d0ddab16b063a4cbb2fd6f99a
|
Provenance
The following attestation bundles were made for sf_synth-0.4.0-py3-none-any.whl:
Publisher:
publish.yml on aypareek/snowflake-synthesizer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sf_synth-0.4.0-py3-none-any.whl -
Subject digest:
f187fe01f62d07a624b7f9025aa49b6585b6b8227f10f5a5425eb43994329b0d - Sigstore transparency entry: 1493871135
- Sigstore integration time:
-
Permalink:
aypareek/snowflake-synthesizer@e47bbb96fbceacbbe1a34a925ae1a7cfa2bec51b -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/aypareek
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e47bbb96fbceacbbe1a34a925ae1a7cfa2bec51b -
Trigger Event:
push
-
Statement type: