PostgreSQL · pg_dump · test data

PostgreSQL test data generator: populate a Postgres database with foreign keys that resolve.

Read your pg_dump schema or connect live on port 5432 and populate a Postgres database where declared foreign keys resolve. Get SQL in topological insert order, load it with psql "$DATABASE_URL" -f seed.sql, and pin a seed for reproducible CI. SERIAL and IDENTITY keys, JSONB, text[] arrays, uuid, citext, numeric, timestamptz and ENUM types from CREATE TYPE are handled, tested against a real 20-app Django project with 226 tables.

Free tier · no card · EU-hosted · zero trackers

Other databases: MySQL test data · generic SQL · Prisma

From pg_dump schema to populated Postgres

Paste a pg_dump --schema-only file or your CREATE TABLE DDL in the web app, push from the VS Code or PyCharm plugin, or use the CLI. The parser reads SERIAL and GENERATED ALWAYS AS IDENTITY primary keys, REFERENCES clauses across the public and other schemas, ENUM types declared with CREATE TYPE, and DEFERRABLE constraints, so the generated rows satisfy them.

DDL in, SQL out
CREATE TYPE order_status AS ENUM ('pending','paid','shipped');

CREATE TABLE app_user (
    id          BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    email       CITEXT UNIQUE NOT NULL,
    tags        TEXT[] DEFAULT '{}',
    created_at  TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE "order" (
    id          SERIAL PRIMARY KEY,
    user_id     INTEGER NOT NULL REFERENCES app_user(id),
    status      order_status NOT NULL,
    total       NUMERIC(10,2) NOT NULL,
    metadata    JSONB NOT NULL DEFAULT '{}'
);

-- → INSERT INTO app_user ... 200 rows, citext emails unique
-- → INSERT INTO "order" ... user_id resolves (declared FK),
--    status ∈ enum, total numeric, metadata valid JSONB,
--    2-19 orders per user, long-tail distributed

What you get

FK-consistent

Declared foreign keys resolve

Children reference parents that exist, including self-references and one-to-one relations. Inserts come out in topological FK order, so the SQL loads into a constrained Postgres schema with \copy or psql as-is.

pg-types

Real Postgres types

SERIAL and BIGSERIAL keys, JSONB objects, text[] arrays, uuid (gen_random_uuid()-style values), citext, numeric, timestamptz and ENUM values from CREATE TYPE, plus generated columns left to the database.

realistic

Production-like distributions

Not every user has exactly 5 orders: long-tail and normal distributions create the skew where pagination and N+1 bugs actually show up.

current

Time-aware data

timestamptz values generate relative to today, so "last 30 days" dashboards stay populated instead of going empty as fixtures age.

reproducible

Deterministic per seed

Same seed, same data, reproducible CI runs. Export the generation config as JSON and commit it next to your migrations.

editor

VS Code & PyCharm plugins

Push your schema to SeedBase in one click, it lands parsed and ready to generate against your Postgres tables.

How it loads into Postgres

Read the schema

Paste pg_dump --schema-only output, raw CREATE TABLE DDL, or connect live on host and port 5432. SERIAL, IDENTITY, REFERENCES, CREATE TYPE enums and DEFERRABLE constraints are parsed.

Generate FK-consistent rows

Rows are produced in topological order from the declared foreign keys: parents before children, self-FKs row by row, uuid and JSONB filled with plausible values.

Export or push

Download a SQL dump for psql, CSV for COPY FROM / \copy, or JSON, or push straight into a live Postgres connection with constraints enabled.

Tested against a real project with 20 apps and 226 tables: declared foreign keys resolve, ENUM columns stay inside their CREATE TYPE values, and the SQL imports under enabled constraints without manual reordering. SeedBase does not invent constraints your schema never declared.

CREATE TABLE with a foreign key to FK-consistent INSERTs

Give SeedBase the same CREATE TABLE DDL Postgres already enforces and it walks the declared REFERENCES clauses to build a dependency graph. Rows come back as plain INSERT statements in topological order: every parent is inserted before any child that points at it, so a user_id always names an app_user(id) that already exists.

-- schema.sql (what Postgres enforces)
CREATE TABLE app_user (
    id          SERIAL PRIMARY KEY,
    email       CITEXT UNIQUE NOT NULL
);
CREATE TABLE "order" (
    id          SERIAL PRIMARY KEY,
    user_id     INTEGER NOT NULL REFERENCES app_user(id),
    total       NUMERIC(10,2) NOT NULL
);
-- seed.sql (generated, FK order: parents first)
INSERT INTO app_user (id, email) VALUES
  (1, 'mara.feldt@example.org'),
  (2, 'jon.aldous@example.net');

INSERT INTO "order" (id, user_id, total) VALUES
  (1, 1, 48.90),   -- user_id 1 exists above
  (2, 1, 132.00),
  (3, 2, 7.50);

Because the order is derived from the constraints themselves, the file loads into a schema with foreign keys enabled, no SET CONSTRAINTS juggling and no manual reordering. Self-referencing keys (an employee.manager_id REFERENCES employee(id)) are emitted row by row so each reference points at an earlier row. The same FK graph drives FK-complete subsetting when you pull a slice of a live database: pick the parent rows you want and every referenced row comes with them.

Load the SQL with psql -f seed.sql

The SQL export is a flat file of INSERT statements, so loading it is one command. Point psql at your database URL and run the file:

# generate seed.sql, then load it into Postgres
psql "$DATABASE_URL" -f seed.sql

# or against a local database by name
psql -d myapp_test -f seed.sql

Prefer bulk load? Export CSV instead and stream it with \copy from the client or COPY FROM on the server, one file per table in FK order:

\copy app_user FROM 'app_user.csv' WITH (FORMAT csv, HEADER true);
\copy "order"   FROM 'order.csv'    WITH (FORMAT csv, HEADER true);

Or skip files entirely and push straight into a live connection (host, port 5432, database) from the web app or CLI, with constraints enabled the whole time.

Deterministic Postgres seed data for CI

Pass a fixed seed and the same schema produces the same rows on every run, so a failing test reproduces locally with the same data. With the Node client @seedbase/client you generate and download({ format: 'sql' }) in a pipeline step, then load the file before the suite:

// seed-sql.mjs, run in CI
import { SeedbaseClient } from "@seedbase/client";
import { writeFile } from "node:fs/promises";

const client = new SeedbaseClient({ token: process.env.SEEDBASE_TOKEN });
const gen = await client.generate(process.env.SEEDBASE_PROJECT, { seed: 42, wait: true });
await writeFile("seed.sql", await client.download(gen.id, { format: "sql" }));
# .github/workflows/test.yml
- run: node seed-sql.mjs
- run: psql "$DATABASE_URL" -f seed.sql

Other stacks reach the same SQL output without Node: the CLI, the VS Code and PyCharm plugins, or the web app all export a SQL dump you load with psql -f. The full API and download options are in the docs.

FAQ

Does it handle SERIAL primary keys and JSONB columns?

Yes. SERIAL, BIGSERIAL and GENERATED ALWAYS AS IDENTITY columns are treated as auto-incrementing keys, so foreign keys have stable integers to point at. JSONB columns get plausible structured objects, text[] arrays get array literals, and uuid columns can use gen_random_uuid() style values.

Can it read my pg_dump?

Yes. Paste a pg_dump --schema-only file or any CREATE TABLE DDL, or connect live on port 5432. The parser reads SERIAL and IDENTITY keys, REFERENCES clauses across schemas, ENUM types from CREATE TYPE, and DEFERRABLE constraints, then generates rows that satisfy them.

In what order are the INSERT statements emitted?

Tables are sorted in topological order from the declared foreign keys, so parents are inserted before children and a constrained schema loads with \copy or psql without reordering. Self-referencing foreign keys load row by row so each reference points at an earlier row.

How do I load the generated data into Postgres?

Download a SQL dump and run it with psql, use COPY FROM or \copy for the CSV export, or push directly into a live Postgres connection (host, port 5432, database). Inserts come out in FK order, so timestamptz, numeric and JSONB values land in a schema with constraints enabled.

How do I populate a Postgres database from a CREATE TABLE schema?

Paste your CREATE TABLE DDL or a pg_dump --schema-only file, set how many rows you want, and download seed.sql. The file is INSERT statements in topological FK order, so loading it with psql "$DATABASE_URL" -f seed.sql populates parents before children and every foreign key resolves. You can also push straight into a live connection instead of writing a file.

Can I run it with psql -f seed.sql?

Yes. The SQL export is a flat file of INSERT statements, so psql "$DATABASE_URL" -f seed.sql or psql -d myapp_test -f seed.sql loads it in one command with foreign keys enabled. For bulk loads, export CSV and stream it with \copy or COPY FROM, one file per table in FK order.

Is the generated data deterministic for CI?

Yes. Pass a fixed seed (for example seed: 42) and the same schema produces the same rows on every run, so a failing test reproduces locally with the same data. With the Node client @seedbase/client you generate and download({ format: 'sql' }) in a pipeline step, then load seed.sql before the suite. A pinned reference date keeps timestamptz values reproducible too.

Two minutes to a fully populated Postgres database

Sign up, read your pg_dump or connect live, generate. No sales call, no credit card, the free tier is enough for a real first impression.

  • FK-consistent
  • JSONB / arrays / uuid
  • SQL / CSV / JSON
  • EU-hosted
Start free

Other stacks: generic SQL test data · MySQL · Django · Prisma  ·  Compare: vs Mockaroo · vs Faker  ·  Anonymize prod data