TypeORM seed data

TypeORM + PostgreSQL test data without writing entity factories. The schema drives generation.

TypeORM projects seed through a hand-written script: initialize a DataSource, then repository.save() rows built from entity factories or a Faker loop. It works for a single entity and grows brittle the moment relations appear. This guide shows the TypeORM-native seeding workflow, where it breaks, and the schema-driven alternative.

How TypeORM seeding normally works

TypeORM handles schema changes with migrations (typeorm migration:generate, typeorm migration:run). Seeding is not built in — teams write a script that initializes the data source and inserts rows:

// src/seed.ts
import { AppDataSource } from "./data-source";
import { User } from "./entity/User";
import { faker } from "@faker-js/faker";
 
await AppDataSource.initialize();
 
const users = AppDataSource.getRepository(User);
for (let i = 0; i < 50; i++) {
  await users.save({
    email: faker.internet.email(),
    name: faker.person.fullName(),
  });
}

Fine for one table. The moment Order has a relation to User, the script has to save the user, read the generated id back, and attach it to the order — dependency order becomes manual bookkeeping.

Where TypeORM seed scripts break

  1. Relations. repository.save() cascades only if you configure it and wire the objects together by hand. Without that, children are saved with a null or hard-coded foreign key, and the failure surfaces later as an orphaned row.
  2. Schema drift. A new NOT NULL column, an enum, a CHECK constraint — each one is a seed change. The entity and migration move; the seed script does not, and tests start failing for reasons nobody can explain.
  3. Uniform randomness. A Faker loop produces plausible values, not production distributions. If your real status column is 70% active, a flat loop gives you roughly a third of each — and query plans in tests stop matching production.

Schema-driven seeding with Weavori

Weavori reads the database schema — the one TypeORM migrated — and generates rows from it. The TypeORM-specific workflow:

1. Run migrations as usual
$ npx typeorm migration:run -d dist/data-source.js
2. Seed from the schema
$ npx --yes @weavori/cli generate postgres://localhost:5432/mydb --rows 1000

Weavori introspects tables, foreign keys, types, and constraints, resolves dependency order (parents before children), and writes via COPY. Every generated order.user_id references a real generated user — by construction, not by cascade configuration.

The schema is the seed

When a TypeORM migration changes the schema, the generated data changes with it. There is no seed script to update because nothing in the script duplicated the schema.

TypeORM + Weavori in CI

The loop that keeps test databases honest:

$ npx typeorm migration:run -d dist/data-source.js
$ npx --yes @weavori/cli generate $TEST_DATABASE_URL --rows 1000 --output plain

Weavori supports API keys for headless auth, standardized exit codes, and offline license validation — CI runners on restricted networks don't phone home. Full GitHub Actions / GitLab / CircleCI / Jenkins examples in the CI/CD guide.

Which TypeORM seed command do you need?

GoalCommand
Apply pending migrations before seedingnpx typeorm migration:run
Emit a migration from entity changesnpx typeorm migration:generate
Sync entities with no migration filesnpx typeorm schema:sync
Run a seed script (TypeORM ships none)ts-node src/seed.ts
Generate a production-shaped dataset with no seed scriptnpx --yes @weavori/cli generate postgres://localhost:5432/mydb

npx typeorm migration:run

typeorm migration:run executes every pending migration in order. TypeORM has no seeding hook of its own, so this is the schema half of the workflow and your seed script is the data half. Run it first, then seed — the rows have to fit the columns the migrations just created.

npx typeorm migration:generate

typeorm migration:generate compares your entities against the live database and writes the migration that closes the gap. Entities and migrations stay in sync with each other; the seed script is checked against neither, which is exactly how it drifts.

npx typeorm schema:sync

typeorm schema:sync pushes the entity definitions straight onto the database with no migration files. It is a prototyping shortcut, not a deploy step — it can drop columns it no longer recognizes. Acceptable for a scratch database you are about to regenerate anyway.

ts-node src/seed.ts

Running the seed script is the seeding command in TypeORM; there is no typeorm db:seed. The script initializes a DataSource, saves parents, reads their generated ids back, and attaches them to children. That ordering logic is the part that breaks: it is invisible, unchecked by the compiler, and surfaces later as an orphaned row or a foreign-key violation. Point Weavori at the migrated database instead and the ordering is computed from the foreign keys.

When to keep your TypeORM seed

Honesty about boundaries: keep a seed script for deterministic unit-test fixtures — a known user the test asserts against. Keep Faker for single values inside tests. Weavori replaces the dataset problem: filling dev, staging, and CI databases with production-shaped, FK-intact rows.

Ready to generate your first dataset?

Install Weavori in one command and connect to any PostgreSQL database.

$npm install -g @weavori/cli
macOS · Linux · Windows/No dependencies required

No credit card required. Start with a 14-day free trial of Pro, then free tier or subscribe.