Performance
240,964 rows per second on a realistic twelve-column schema — 1,000,000 rows of order data written to CSV in 4.15 s.
Every number on this page was measured, not estimated - written into the site directly by the run that produced it, so nothing here is a figure somebody typed in by hand. The schema behind the headline is below, so you can confirm it on your own machine.
Measured on
Intel(R) Core(TM) Ultra 9 275HX · 24 logical cores ·
HippoDatamus 0.5.0, 2026-08-22. Each measurement was run 3 times and the fastest kept, because a slower run measured something else happening on the machine.
By scenario
Five shapes that look like real work, each generating 100,000 rows to CSV. Not eight Guid columns — money, dates, unique ids, pick lists, templates and spreadsheet lookups all cost something, and a benchmark that avoided them would produce a bigger number and tell you nothing.
| Scenario | Columns | Rows/second | Time | Output |
|---|---|---|---|---|
| Retail ordersOrder lines: ids, money, dates, a templated order number, and two pick lists. | 0 | 151,515 | 660 ms | 16.3 MB |
| Healthcare patientsA patient index with a templated record number, addresses, and dates of birth. | 0 | 69,444 | 1.44 s | 17.8 MB |
| Financial transactionsA ledger: account numbers, amounts, currencies, and timestamps. | 0 | 125,000 | 800 ms | 13.5 MB |
| IoT telemetrySensor readings - a device id, timestamps, and normally distributed values. | 0 | 250,000 | 400 ms | 8.5 MB |
| CRM contactsContacts whose owner and departments are looked up from a real spreadsheet. | 0 | 79,365 | 1.26 s | 20.9 MB |
By output format
The same schema, written three ways.
| Format | Rows/second | Time | Output |
|---|---|---|---|
| CSV | 153,846 | 650 ms | 16.3 MB |
| JSON | 70,922 | 1.41 s | 32.8 MB |
| XLSX | 40,650 | 2.46 s | 11.3 MB |
CSV is the fastest thing to write and the cheapest to read back. Excel has to build a worksheet and its styles, and it caps out at 1,048,576 rows — past that, use CSV.
By row count
| Rows | Rows/second | Generation | Wall clock | Output |
|---|---|---|---|---|
| 10,000 | 55,556 | 180 ms | 332 ms | 1.6 MB |
| 100,000 | 136,986 | 730 ms | 887 ms | 16.3 MB |
| 1,000,000 | 240,964 | 4.15 s | 4.32 s | 163.4 MB |
Throughput improves with size, which is the shape you want: a run has fixed costs that are paid once and stop mattering. Wall clock includes process startup and flushing the file to disk, which is what you actually wait for; generation is the run itself. The gap is visible at ten thousand rows and irrelevant at a million.
Memory stays flat
A million-row CSV costs about as much memory as a thousand-row one, so the row count you ask for is not limited by the machine you ask on. Excel is the exception — a worksheet has to be assembled, and it caps out at 1,048,576 rows regardless.
What costs time
Roughly in order, if you are trying to make a large run quicker:
- Excel output. A worksheet is more work than a line of text. Use CSV for volume.
- Unique constraints, when they cover most of a column's possible values. Distinct values cost more than random ones.
- Templates and file-backed columns, mildly. A template depends on other columns, and a file-backed column has a file to read.
- Column count, linearly. Twice the columns is roughly twice the time.
Row count itself is nearly free per row, which is the point: going from a hundred thousand rows to a million costs about ten times as much, not a hundred.
Check it yourself
Nothing here needs to be taken on trust. This is the schema behind every retail-orders number above — save it, and run it with the command-line tool from your download:
hippodatamus-cli --config retail-orders.yaml --rows 1000000 --output orders.csvretail-orders.yaml
Output:
Path: orders.csv
Format: CSV
Schema:
RowCount: 100000
GlobalSeed: 20260822
Columns:
- Id: aaaa0001-0000-0000-0000-000000000001
Name: order_id
Generator:
Type: Guid
- Id: aaaa0001-0000-0000-0000-000000000002
Name: order_number
Generator:
Type: Template
Settings:
Template: "ORD-{seq:000000}"
- Id: aaaa0001-0000-0000-0000-000000000003
Name: seq
IsExcludedFromOutput: true
Generator:
Type: Sequential Id
- Id: aaaa0001-0000-0000-0000-000000000004
Name: customer_name
Generator:
Type: Full Name
- Id: aaaa0001-0000-0000-0000-000000000005
Name: email
Generator:
Type: Email
Settings:
UseFixedDomain: true
- Id: aaaa0001-0000-0000-0000-000000000006
Name: product
Generator:
Type: Product Name
- Id: aaaa0001-0000-0000-0000-000000000007
Name: quantity
Generator:
Type: Integer
Settings:
Min: 1
Max: 25
- Id: aaaa0001-0000-0000-0000-000000000008
Name: unit_price
Generator:
Type: Price
Settings:
Min: 5
Max: 500
Decimals: 2
- Id: aaaa0001-0000-0000-0000-000000000009
Name: status
Generator:
Type: Pick List
Settings:
ValueType: String
Values: [Placed, Picking, Shipped, Delivered, Returned]
- Id: aaaa0001-0000-0000-0000-000000000010
Name: channel
Generator:
Type: Pick List
Settings:
ValueType: String
Values: [web, app, phone, in-store]
- Id: aaaa0001-0000-0000-0000-000000000011
Name: ordered_at
Generator:
Type: Date
Settings:
Min: 2024-01-01
Max: 2026-06-30
- Id: aaaa0001-0000-0000-0000-000000000012
Name: ships_on
Generator:
Type: Date
Settings:
Min: 2024-01-02
Max: 2026-07-15
IncludeTime: falseYour numbers will differ with your hardware. The shapes should not.