Effortless targeted database seeding for query optimization & performance testing
Key Features β’ Ideal Workflow β’ Configuration β’ Performance
deed.mp4
- Optimizing at Scale: Your app is growing and your database is pulling heavy weight. You need realistic volume to continuously benchmark and refine your SQL queries and indexes.
- Zero Prod Data Access: You don't have access to production databases due to strict compliance, privacy, or security regulations.
- Realistic Load Testing: You need a quick, painless way to generate massive datasets locally without spending days writing custom seed scripts.
- You already have unrestricted access to a fully populated, compliant production database dump.
- Your workflow relies entirely on strict double-validation of business logic at the UI/API layer for test data.
# TODO: Not ready for a stable release| Category | Status | Supported Types |
|---|---|---|
| Numeric | β | int2, int4, int8, numeric, decimal, float4, float8, serial, bigserial |
| Character | β | varchar, char, text, bpchar |
| Boolean | β | boolean |
| UUID | β | uuid |
| Arrays | β | text[], int[], etc. |
| Network | β | inet, cidr, macaddr, macaddr8 |
| Enum | β | Custom ENUM types |
| Date & Time | β | date, time, timetz, timestamp, timestamptz, interval |
| JSON | β³ | json, jsonb (Planned) |
| Binary | β³ | bytea (Planned) |
| Ranges | β³ | int4range, numrange, tsrange, tstzrange, daterange (Planned) |
| Full-Text | β³ | tsvector, tsquery (Planned) |
| Geometric | β³ | point, line, lseg, box, path, polygon, circle (Planned) |
| Bit Strings | β³ | bit, bit varying (Planned) |
| Composite | β³ | User-defined composite types (Planned) |
| Constraint / Feature | Status | Notes / Sub-features |
|---|---|---|
| Primary Key | β | Supported |
| Not Null | β | Supported |
| Unique | β | Supported |
| Default Expressions | β | Supported |
| Generated Columns | β | GENERATED AS IDENTITY, GENERATED ALWAYS AS (...) STORED |
| Simple Foreign Key | β | Resolved across parent dependencies |
| Composite Foreign Key | β³ | (Planned) |
| Self-Referencing FK | β³ | (Planned) |
| Check Constraints | β³ | (Planned) |
| Exclusion Constraints | β³ | (Planned) |
| Timing Modifiers | β³ | DEFERRABLE, INITIALLY DEFERRED / IMMEDIATE (Planned) |
Note
Targeted Ingestion: Because SQL queries and index strategies change alongside your UI/UX features, deed is built for targeted iterationsβnot for dumping generic data into your entire schema once and forgetting about it.
- Spin up a clean DB container with your latest migrations applied.
- Identify target tables involved in the specific query or feature you are optimizing.
- Seed mock data into those specific tables (and their required parent dependencies) using
deed. - Benchmark & rewrite your SQL queries and indexes against realistic data scales.
- Destroy the container and repeat for the next iteration.
To customize how mock data is generated, create a deed.json file in your project directory:
Tip
Commit your primary deed.json to Git so your team shares base generator rules. When working locally, copy it over, adjust row counts/patterns as needed, and feed your local config to deed.
Ingest 1,000,000 rows into the app and users tables (along with any required foreign-key parent dependencies):
deed seed \
--dsn "postgres://postgres:my_secure_password@127.0.0.1:5433/postgres" \
--tables=app,users \
--count=1000000 \
--config=deed.jsonIngestion throughput is impacted by four core variables:
- Dependency depth (number of parent tables requiring resolved FK relationships).
- Column complexity (mix of standard scalars vs. regex/custom types).
- Total column count per table.
- Database host system specifications.
| Target Dataset | Tables Ingested | Total Rows | Execution Time |
|---|---|---|---|
| Complex Relational Tree | 10 tables | 5.00M+ | 16.27s |
| Single Table | 1 table | 20.00M | 60.08s |
| Massive Flat Ingestion | 1 table | 67.00M | ~1.5m |
View Test Run Output
Dependencies for 'proof_verifications'
π proof_verifications
β°ββ π delivery_proofs
β°ββ π shipment_tracking_events
β°ββ π shipments
βββ π orders
β β°ββ π users
βββ π shipping_carriers
β°ββ π user_addresses
βββ π users
β°ββ π countries
Dependencies for 'system_event_logs'
π system_event_logs
Seeding Data (10 tables)
countries 50 / 50 [βββββββββββββββββββββββββββββββββββββββββββββ] 100 % 500000 rows/s β Done
users 200 / 200 [βββββββββββββββββββββββββββββββββββββββββββββ] 100 % 2.00M rows/s β Done
orders 300 / 300 [βββββββββββββββββββββββββββββββββββββββββββββ] 100 % 3.00M rows/s β Done
system_event_logs 1000000 / 1000000 [βββββββββββββββββββββββββββββββββββββββββββββ] 100 % 422353 rows/s β Done
shipping_carriers 1000000 / 1000000 [βββββββββββββββββββββββββββββββββββββββββββββ] 100 % 306030 rows/s β Done
user_addresses 1000000 / 1000000 [βββββββββββββββββββββββββββββββββββββββββββββ] 100 % 248877 rows/s β Done
shipments 100 / 100 [βββββββββββββββββββββββββββββββββββββββββββββ] 100 % 1.00M rows/s β Done
shipment_tracking_events 1000000 / 1000000 [βββββββββββββββββββββββββββββββββββββββββββββ] 100 % 392016 rows/s β Done
delivery_proofs 1000000 / 1000000 [βββββββββββββββββββββββββββββββββββββββββββββ] 100 % 190499 rows/s β Done
proof_verifications 100 / 100 [βββββββββββββββββββββββββββββββββββββββββββββ] 100 % 1.00M rows/s β Done
β¨ Ingestion complete across all tables. Took 16.27 seconds
Dependencies for 'system_event_logs'
π system_event_logs
Seeding Data (1 tables)
system_event_logs 20000000 / 20000000 [βββββββββββββββββββββββββββββββββββββββββββ] 100 % 357122 rows/s β Done
β¨ Ingestion complete across all tables. Took 60.08 seconds
Dependencies for 'warehouse_shelf_grid'
π warehouse_shelf_grid
Seeding Data (1 tables)
warehouse_shelf_grid 67000000 / 67000000 [βββββββββββββββββββββββββββββββββββββββββββ] 100 % 880227 rows/s β Done
β¨ Ingestion complete across all tables. Took 99.01 seconds
{ "version": "1", "database": { "name": "postgres" }, "rules": { "ignore_tables": [ "schema_migrations" ], "tables": { "users": { // Row count here overrides the CLI flag for this table "count": 200, "columns": { "username": { "type": "regex", // Define business logic requirements using RE2-compatible regex "pattern": "^[a-zA-Z0-9_-]{3,30}$" }, "password_hash": { "type": "regex", "pattern": "^\\$2[ayb]\\$[0-9]{2}\\$[A-Za-z0-9./]{53}$" } } }, "countries": { "count": 50 } } } }