On this page

Database Seeding in Python

Misata generates synthetic relational data and loads it directly into a database. No migration scripts. No manual INSERT loops. No orphan rows.

Quick start#

Python
import misata
from misata import seed_database

# Generate + seed in two lines
tables = misata.generate("A SaaS company with 1000 users.", seed=42)
report = seed_database(tables, "sqlite:///./dev.db", create=True)

print(report.total_rows)   # 6,000+
print(report.table_rows)   # {"users": 1000, "subscriptions": 3000, ...}

Supported databases#

Misata uses SQLAlchemy under the hood, any SQLAlchemy-compatible database works:

Python
# SQLite (local dev)
seed_database(tables, "sqlite:///./local.db", create=True)

# PostgreSQL
seed_database(tables, "postgresql://user:pass@localhost/mydb", create=True)

# MySQL / MariaDB
seed_database(tables, "mysql+pymysql://user:pass@localhost/mydb", create=True)

Truncate before seeding (CI / staging)#

Python
report = seed_database(
    tables,
    "postgresql://user:pass@staging-db/app",
    create=True,    # CREATE TABLE IF NOT EXISTS
    truncate=True,  # TRUNCATE before INSERT
)

Use truncate=True in CI pipelines to reset the database to a known state before each test run.

Seed from a story (CLI)#

Shell
misata generate \
  --story "A SaaS company with 1000 users" \
  --rows 1000 \
  --db-url sqlite:///./dev.db \
  --db-create \
  --db-truncate

Seed into existing SQLAlchemy models#

If your project already uses SQLAlchemy ORM models, Misata can introspect them and seed against the existing schema:

Python
from misata import seed_from_sqlalchemy_models
from myapp.models import Base, engine

report = seed_from_sqlalchemy_models(
    Base,
    engine,
    story="A SaaS company with 500 users",
    truncate=True,
)
print(report.total_rows)

Introspect an existing database#

Misata can read a live database and generate a matching SchemaConfig, then generate data that fits your existing table structure:

Python
from misata import schema_from_db, generate_from_schema

schema = schema_from_db("postgresql://user:pass@localhost/mydb")
print(schema.summary())  # shows your real table structure

# Generate data that matches your actual schema
tables = generate_from_schema(schema)

Why Misata works well for seeding#

Database seeding breaks in predictable ways:

ProblemWhat usually happensMisata
FK violationsChild rows reference missing parentsTables generated in dependency order; FK values sampled from valid parent pool
Flat distributionsAll rows look the sameDomain priors: log-normal amounts, Zipf categories, real demographic frequencies
Scale mismatchChild table has wrong number of rowsRow counts planned proportionally per relationship
RepeatabilityTests produce different data each runseed=42 makes generation fully deterministic

Batch size control#

For large databases, control memory usage with batch_size:

Python
report = seed_database(
    tables,
    "postgresql://user:pass@localhost/prod_clone",
    batch_size=10_000,  # INSERTs in batches of 10k rows
    create=True,
    truncate=True,
)

Example: seed a test database in pytest#

Python
# conftest.py
import pytest
import misata
from misata import seed_database
from sqlalchemy import create_engine

@pytest.fixture(scope="session")
def db_engine():
    engine = create_engine("sqlite:///./test.db")
    return engine

@pytest.fixture(scope="session", autouse=True)
def seed_test_db(db_engine):
    tables = misata.generate("A SaaS company with 100 users.", seed=42)
    seed_database(tables, db_engine, create=True, truncate=True)

Every test run starts from a fresh, realistic seed. seed=42 means the data is identical across runs, so test assertions stay stable.

Prefer generating data visually?

Misata Studio lets you turn natural language prompts into relational schemas with exact outcome invariants, live preview tables, and one-click database seeding without writing code.

Last updated Edit this page.md