Skip to content

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.

ScenarioColumnsRows/secondTimeOutput
Retail ordersOrder lines: ids, money, dates, a templated order number, and two pick lists.0151,515660 ms16.3 MB
Healthcare patientsA patient index with a templated record number, addresses, and dates of birth.069,4441.44 s17.8 MB
Financial transactionsA ledger: account numbers, amounts, currencies, and timestamps.0125,000800 ms13.5 MB
IoT telemetrySensor readings - a device id, timestamps, and normally distributed values.0250,000400 ms8.5 MB
CRM contactsContacts whose owner and departments are looked up from a real spreadsheet.079,3651.26 s20.9 MB

By output format

The same schema, written three ways.

FormatRows/secondTimeOutput
CSV153,846650 ms16.3 MB
JSON70,9221.41 s32.8 MB
XLSX40,6502.46 s11.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

RowsRows/secondGenerationWall clockOutput
10,00055,556180 ms332 ms1.6 MB
100,000136,986730 ms887 ms16.3 MB
1,000,000240,9644.15 s4.32 s163.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:

  1. Excel output. A worksheet is more work than a line of text. Use CSV for volume.
  2. Unique constraints, when they cover most of a column's possible values. Distinct values cost more than random ones.
  3. Templates and file-backed columns, mildly. A template depends on other columns, and a file-backed column has a file to read.
  4. 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:

bash
hippodatamus-cli --config retail-orders.yaml --rows 1000000 --output orders.csv
retail-orders.yaml
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: false

Your numbers will differ with your hardware. The shapes should not.

Proprietary software, free to use. Licence · Privacy