Quick Start
This guide takes you from zero to a seeded database. If you already have migrations applied and a connection string handy, you’re about 60 seconds away.
Prerequisites
Section titled “Prerequisites”- Node.js 18 or newer (
node -vto check) - An existing database with your schema already applied. Seedforge reads your tables — it does not create them. Run your migrations first (
prisma migrate dev,drizzle-kit push,rails db:migrate, whatever you use). - A connection string for PostgreSQL, MySQL, or SQLite — or an ORM schema file if you want SQL output without a live database.
Install
Section titled “Install”Pick whichever fits your workflow.
# Global install — one-off usage from any shellnpm install -g @otg-dev/seedforge
# Project dev dependency — reproducible in CInpm install --save-dev @otg-dev/seedforge
# No install — just run itnpx @otg-dev/seedforge --db postgres://localhost/mydbYour first seed
Section titled “Your first seed”Point Seedforge at a database and pass --count to choose rows per table:
seedforge --db postgres://localhost/myapp --count 50Expected output:
seedforge v2.4.0Introspected 8 tables, 2 enums, 12 foreign keysInsert order: countries -> users -> categories -> products -> orders -> order_items -> reviews -> audit_logGenerated 400 rows across 8 tables
Seeding complete: Tables: 8 Rows: 400 Time: 142ms Mode: DIRECTQuery any table and you’ll see realistic data instead of user_1, user_2:
SELECT first_name, last_name, email FROM users LIMIT 3; first_name | last_name | email------------+-----------+---------------------------- Marcus | Chen | marcus.chen@example.com Fatima | Okafor | fatima.okafor@example.com Lena | Johansson | lena.johansson@example.comAll generated emails use RFC 2606 reserved domains (@example.com) so no stray test mail ever lands on a real inbox.
Deterministic mode
Section titled “Deterministic mode”Pass --seed <number> to get identical output every run. Same seed, same rows, every time.
seedforge --db postgres://localhost/myapp --count 50 --seed 42Preview without touching the DB
Section titled “Preview without touching the DB”--dry-run runs the full pipeline but skips the final INSERT:
seedforge --db postgres://localhost/myapp --count 50 --dry-run--output writes a .sql file you can inspect, version, or apply later with psql:
seedforge --db postgres://localhost/myapp --count 50 --output seed.sqlpsql $DATABASE_URL < seed.sqlFrom an ORM schema file
Section titled “From an ORM schema file”You don’t need a running database at all if you just want SQL out. Prisma, Drizzle, TypeORM, and JPA schemas all work with --output:
seedforge --prisma ./prisma/schema.prisma --count 100 --output seed.sqlseedforge --drizzle ./src/db/schema.ts --output seed.sqlseedforge --typeorm ./src/entities/ --output seed.sqlseedforge --jpa ./src/main/java/com/example/entities/ --output seed.sqlIn your test suite
Section titled “In your test suite”withSeed() is the test-friendly entry point. It lazily connects, wraps everything in a transaction, and rolls back on teardown so tests never pollute each other.
import { withSeed } from '@otg-dev/seedforge'import { describe, it, afterAll, expect } from 'vitest'
describe('user API', () => { const { seed, teardown } = withSeed(process.env.TEST_DATABASE_URL!, { seed: 42, transaction: true, })
afterAll(teardown)
it('lists users', async () => { const users = await seed('users', 10) const res = await fetch('/api/users') expect(await res.json()).toHaveLength(10) })})Production safety
Section titled “Production safety”Seedforge inspects connection strings for production-like hostnames — RDS, Cloud SQL, Supabase, Neon, PlanetScale, and friends — and refuses to run unless you confirm. Pass --yes to skip the prompt in automation.
# CI against an ephemeral preview DBseedforge --db $PREVIEW_DATABASE_URL --count 50 --seed 42 --quiet --yesNext steps
Section titled “Next steps”- CLI reference — every flag, with examples
- Schema sources — PG, MySQL, SQLite, Prisma, Drizzle, TypeORM, JPA
- Examples — recipes for CI, test suites, large datasets, and weighted enums