Blog
PostgreSQLCLISynthetic Data

Generate Postgres test data with no database

Paste your CREATE TABLE statements and generate referentially intact Postgres data. No database, no connection string, no config. Weavori's DDL paste mode runs from a schema file.

The Weavori TeamSeptember 27, 20265 min read

To generate test data, you usually need a database first. That order is backwards. Generation needs one input: the schema. And a schema is just text. If you can paste your CREATE TABLE statements, you can generate data.

Weavori's DDL paste mode reads CREATE TABLE statements from a file or stdin and generates rows from them. No connection string, no server to start, no Docker. Output is a JSON array (default) or CSV on stdout.

Generate from a schema file

Save your schema to schema.sql, then run:

$npx --yes @weavori/cli generate --input schema.sql --input-format ddl --rows 100

--rows 100 generates 100 rows per table, written to stdout as JSON. Add --format csv for CSV:

$npx --yes @weavori/cli generate --input schema.sql --input-format ddl --rows 100 --format csv

Or read the DDL from stdin and pipe it:

$cat schema.sql | npx --yes @weavori/cli generate --stdin --input-format ddl --format csv
✓

One login, then offline

Paste mode runs locally, but Weavori still needs to know who you are. Run weavori login once, or set WEAVORI_API_KEY for headless use. Generation itself does not call home.

What it parses

Paste mode reads CREATE TABLE statements, including schema-qualified names (public.users), IF NOT EXISTS, and inline or table-level PRIMARY KEY, FOREIGN KEY ... REFERENCES, UNIQUE, and CHECK constraints.

Here is a schema you can paste as-is:

CREATE TABLE users (
  id         bigint PRIMARY KEY,
  first_name text NOT NULL,
  last_name  text NOT NULL,
  email      text NOT NULL,
  created_at timestamptz NOT NULL
);
 
CREATE TABLE orders (
  id         bigint PRIMARY KEY,
  user_id    bigint NOT NULL REFERENCES users(id),
  status     text NOT NULL,
  created_at timestamptz NOT NULL
);

Column names steer the values. first_name produces names, email produces emails, status draws from realistic statuses, and created_at produces timestamps. These are the same schema rules the live-database path uses, so the data is shaped by your schema, not by a config file you write.

!

Honest boundaries

As of the shipped v0.1.13, paste mode parses CREATE TABLE statements only. Indexes, sequences, and ALTER statements are ignored. With no source database, there are no statistics to sample, so values come from type and column-name rules rather than a real distribution. Paste mode is PostgreSQL only.

What comes out

Tables generate in foreign-key order: users before orders, and every orders.user_id references a real generated users.id. With more than one table, CSV labels each block:

--- public.users ---
id,first_name,last_name,email,created_at
1,Maya,Okafor,m.okafor@example.com,2026-02-11T08:14:52Z
2,Daniel,Weiss,d.weiss@example.com,2026-03-02T17:40:19Z

--- public.orders ---
id,user_id,status,created_at
1,1,paid,2026-03-05T10:22:01Z
2,1,shipped,2026-03-19T09:03:44Z
i

Representative output

Values differ between runs. The column set, ordering, and foreign keys are exact.

When you want this

  • Before the database exists. Design the schema first, look at the data, and fix names and types while they are still cheap to change.
  • Fixtures without a container. Generate JSON or CSV in the pipeline, then load it into the database your tests already run against.
  • Demos and screenshots. You need realistic rows on a screen, not a provisioned environment.

Write into a database instead

If you do have a Postgres instance, skip stdout and stream the rows in:

$weavori generate --input schema.sql --input-format ddl --target postgres://localhost:5432/app --rows 1000

--create-tables is on by default, so Weavori creates the tables in the target first, then writes the rows with COPY.

Compared to writing the INSERTs

The alternative is a seed script you maintain by hand. Both work. They differ in who keeps the foreign keys straight:

Hand-written seed SQLWeavori paste mode
Foreign keysOrder the inserts and match IDs by handParents generated first, children reference real rows
Realistic valuesWhatever you typedColumn-name rules per type
Schema changeThe script drifts, and you edit itRe-parse the schema, nothing to update
Exact controlFullRules, plus --formula for computed columns

Try it

Paste any CREATE TABLE block you already have. A snippet from a design doc, a migration file, or the schema section of a ticket is enough.