Sample data · CC0
Twenty datasets that behave like real ones.
Sales, customers, orders, weather, stock prices, sensors, logs, tickets, flights and a file that is broken on purpose. Every one is deterministic, every one comes in five formats, and three of them share keys so a join demo actually joins. Take 100 or 1,000 rows as a file, or build a million right here in your browser.
Two years of daily orders across five regions, three channels and eight products. Revenue is exactly units times unit price.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
The default choice for a first dashboard.
A SaaS customer table with plans, monthly revenue and safe fake contact details on reserved example domains.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
Joins to orders and support tickets on customer_id.
Order headers that really join: every customer_id and sku exists in the customers and products datasets, and the totals add up.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
The child table. Join it to customers and products.
A lookup table with SKUs, cost, price, stock and ratings. The first 60 SKUs are the ones the orders dataset buys.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
The dimension table for orders and inventory.
An HR roster with departments, titles, hire dates and salaries that track seniority rather than a flat random range.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
Salary bands track the seniority in the title.
A helpdesk export with response and resolution clocks, priorities and a satisfaction score that is blank until the ticket closes.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
Two columns are blank on purpose. That is the lesson.
Daily campaign performance where clicks never exceed impressions, conversions never exceed clicks, and cost per channel is plausible.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
Six channels, each with its own CTR and cost.
Ten cities, one row per city per day, with a real seasonal curve instead of uniform noise.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
Sydney runs on the opposite season. On purpose.
Eight invented tickers with daily open, high, low, close and volume. The OHLC invariants hold on every row.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
Eight invented tickers. None is a real company.
Forty devices reporting every few minutes, with batteries that drain over the window and statuses that follow the readings.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
Batteries drain monotonically. One reading in 200 is missing.
Access log lines already parsed into columns: method, path, status, bytes, latency and user agent.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
The user agent column has commas in it. Deliberately.
Employee expense claims in four currencies, with approval states and the odd blank field a real export carries.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
Zero-padded ids and four currencies in one column.
An invented film catalogue with budgets, box office and ratings. Nothing here is a real title, so nothing here is a licensing problem.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
Invented titles, so no licensing question.
NPS and satisfaction answers with free-text comments that contain commas, quotes and the occasional newline.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
The comment column has quotes inside quotes.
A statement export with signed amounts and a running balance that actually reconciles, account by account.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
The running balance adds up, account by account.
Stock on hand by warehouse and SKU, with reserved units, reorder points and a cover calculation that holds.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
Shares SKUs and unit cost with the product catalog.
Property listings where price follows size, age and city instead of being drawn at random.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
Price follows size, age and city. Good for regression.
One row per student, subject and term. Long format on purpose, so it is the file to practise pivoting on.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
One row per student, subject and term. Pivot it.
Scheduled and actual departures with a long delay tail, cancellations that leave real blanks, and airport pairs that make sense.
CSV · JSON · JSONL · Excel · Parquet · 100 · 1,000 · up to 1M in the browser
Local timestamps with no zone. That is realistic.
One CSV carrying nine defects at once: ragged rows, duplicate headers, mixed date formats, mojibake, leading zeros, EU decimals, blank rows, mixed line endings and padded cells.
CSV · 100 · 1,000 · up to 1M in the browser
CSV only, because the defects do not survive typed formats.
Why twenty and not the usual three
Search for sample data and you get the same three files over and over: a list of names, a list of cities, and something about superstore sales. They are fine for a screenshot. They are useless for the thing people usually need test data for, which is finding out what happens when the shape of the input changes.
So this collection is built around shapes rather than subjects. There is a wide table and a narrow one. There is a long file meant for pivoting and a short lookup table meant for joining to it. There is a column that is blank a third of the time on purpose, a column of zero-padded keys that Excel will destroy, a timestamp column in UTC and another in local time with no zone at all, and a free-text column with commas and quotation marks inside it. If your parser, your importer or your dashboard has an opinion about any of those, one of these files will find it.
Deterministic, so a test can assert on them
Every file comes out of one seeded generator. The 1,000-row customers file has the same 1,000 rows in the same order for everybody, forever, and the checksum you record today will still match next year. That is what makes these usable in a test suite rather than only in a demo: you can assert a row count, a sum, a checksum or an exact cell, and nothing drifts underneath you.
The in-browser generator runs the same code. When you press "100k rows" the file your browser builds is byte-identical to the file this site would have shipped at that size, because there is only one generator in the repository and the download and the button both call it. Two people on two continents pressing the same button get the same bytes.
Same window at every size
A sample file that squeezes two years of sales into 100 rows and then squeezes the same two years into a million rows is more useful than one that starts on the same day and runs out after a week. Every dated dataset here spreads its rows evenly across a fixed window, so a chart drawn from the 100-row file has the same shape as a chart drawn from the million-row file. Only the density changes.
That is also why the row counts stop at 1,000 as files. Beyond that, hosting a 190 MB download helps nobody. The generator builds those sizes in the tab, in a few seconds, with a progress bar, and hands you the file.
Three of them join
Customers, orders and products share keys on purpose. An order's customer_id is always a real row in the customers file, its sku is always a real row in the products file, and its unit_price is the catalogue price for that SKU, so a three-way join reconciles to the cent. Inventory shares the same SKU space, and support tickets share the same customer space.
That means you can practice the thing people actually get stuck on, which is not reading a CSV but reconciling two of them. Load orders and customers into the Data Explorer, join on customer_id, group by plan, and you have revenue by plan tier in about four clicks.
Safe fake data, public domain
Every dataset here is synthetic. The people are invented, the companies are invented, the tickers are four-letter strings that belong to nobody, the film titles are made up, and every email address is on example.com, which RFC 2606 reserves precisely so test data cannot reach a real inbox. The IP addresses in the web log dataset sit inside 198.51.100.0/24 and 203.0.113.0/24, the ranges RFC 5737 set aside for documentation.
All of it is dedicated to the public domain under CC0 1.0. Use it in a course, a paid product, a book, a conference talk or a bug report, with or without credit.
Questions about the collection
Are these files really free for commercial use?
Yes. Every dataset on this page is dedicated to the public domain under CC0 1.0, which is the closest thing to no license at all. You can ship them inside a paid product, print them in a book, put them in a training course or hand them to a client, with no attribution and nothing to sign. A link back is welcome and it is not a condition.
Will the files change under me?
No. They were produced by a seeded generator and committed as fixed bytes, so the row order, the values and the byte count all stay the same. If a dataset ever needs to change in a way that would break an existing checksum, it will appear at a new name rather than being edited quietly in place. That is deliberate: several of these files exist so that other people's tests can assert on them.
How big can the in-browser generator go?
A million rows, in CSV, JSON or JSONL. On a normal laptop a million rows of the sales dataset takes a few seconds and lands as a file of about 55 MB. The wider datasets, like web server logs, are slower and larger. Nothing is uploaded and nothing is fetched: the rows are computed in your tab and handed to your browser's download machinery as a blob.
Why offer Parquet and Excel as well as CSV?
Because the question people are usually answering is not "can my tool read a CSV" but "does my tool read this file the same way that tool does". Shipping the identical dataset as CSV, JSON, JSONL, Excel and Parquet turns that into a controlled experiment: same rows, same values, five containers. The Parquet files carry real types, which is the fastest way to find out whether your pipeline was relying on a string that looked like a number.
Which one should I start with?
If you want a dashboard in one click, take sales transactions. If you want to practice a join, take orders together with customers and products. If you want to break something on purpose, take the messy data pack. If you are teaching a pivot table, take students and grades, which is deliberately in long format with one row per student, subject and term.
Need something these do not cover?
The test data generator builds a schema of your own, up to a million rows, with the same seeded determinism. The sample files page holds the deliberately broken files, one dataset in fourteen structured formats from Parquet to SQLite, and the purpose-built fixtures each tool loads.
Open the Data Explorer