Avro to CSV Converter
Drop an .avro file and get a table. Nested records become dotted columns, the rows appear on screen before you commit to anything, and the whole conversion happens in your browser. No install, no signup.
Need to drop columns or filter rows first? Open the app
Why a table beats the raw records
Avro is a good wire format and a poor reading format. The moment you want to count something, sort something, or show the file to a person who does not care what a sync marker is, you want columns and rows.
- Handing rows to an analyst. They asked for the events from Tuesday. They did not ask for a binary container and a link to the Avro specification.
- Sanity checking a pipeline. Sort by a column, scan for the value that should never be blank, find out in a minute rather than after the next run.
- Loading into something that only speaks CSV. Plenty of BI tools, CRMs, billing systems and internal admin screens have a CSV import and nothing else.
- Comparing two dumps. Two CSVs diff. Two Avro containers do not, and byte comparison tells you nothing when block boundaries move.
- Getting the field list. The header row of the CSV is a flattened view of the schema, which is often the fastest way to answer what fields does this topic have.
Worked example: a session export with three kinds of nesting
A lake export called sessions-2026-01.avro, two records, with a record inside a record, a map, an array of strings and an array of records. That covers everything a flattener has to make a decision about:
session_id string
device record { os string, screen record { w int, h int } }
utm map<string>
tags array<string>
events array<record { name string, ms int }>
The CSV that comes out, exactly as written:
session_id,device.os,device.screen.w,device.screen.h,utm.source,utm.campaign,tags,events
s-881,iOS 18,390,844,newsletter,jan-relaunch,"[""returning"",""eu""]","[{""name"":""view"",""ms"":0},{""name"":""add_to_cart"",""ms"":8400}]"
s-882,Android 15,412,915,search,,,"[{""name"":""view"",""ms"":0}]"
And above the preview, one note:
2 fields held a list of objects and were kept as JSON text
rather than split into extra rows.
Read the header row and you can see every decision the flattener made. device turned into three columns, one per leaf, with the path spelled out. The map became utm.source and utm.campaign, one column per key that any record used, which is why s-882 has an empty campaign cell rather than a missing field. tags and events both stayed in one cell each as JSON text, and the empty tags array for s-882 landed as an empty cell rather than the two characters for an empty list.
The doubled quotes in those cells are normal CSV quoting, not damage. Excel, Google Sheets and every CSV parser worth using will show you ["returning","eu"] in the cell. If your downstream reader chokes on them, it is not reading quoted fields properly, and the same file will break on any address column with a comma in it.
The four rules the flattener follows
Avro is decoded first, using the schema stored in the file's own header, and then the records are laid out as a rectangle. Four rules decide the shape, and they are the same ones the JSON and XML converters here use, so output from any of them lines up.
- Records become dotted paths. A leaf value gets one column named for the path that reaches it, such as device.screen.w. Four dot separated parts is the limit; a fifth level is written into the fourth column as JSON text, with a note counting how often that happened.
- Maps become columns, one per key. An Avro map is a set of keys chosen at write time rather than at schema time, so each key that appears anywhere in the file gets its own column. This is convenient for a handful of stable keys and awkward for a map used as a bag of anything, which is worth knowing before you convert a file full of them.
- Arrays stay in one cell. They are written as JSON text, and an empty array leaves the cell empty. No row is ever duplicated to unroll a list, because a converter that quietly triples your row count is a converter you cannot trust with a row count.
- Columns are the union of everything seen. First record first, then any new key appended on the right as it turns up. This matters more in Avro than elsewhere, because a union typed field is legitimately absent from some records.
Logical types are resolved on the way through, so a timestamp column reads as an ISO 8601 string and a date column as a calendar date. A decimal keeps its scale as text, which means an amount stored with two decimal places shows as -45.50 rather than -45.5.
Things that surprise people
- Empty and null look identical. A null value, a missing union branch and a key some records never had all produce an empty cell. CSV has no way to tell them apart. If that distinction carries meaning in your data, convert to JSON instead, where null survives as null.
- A wide map makes a wide file. Ten thousand distinct map keys across a file means ten thousand columns, nearly all of them blank. The conversion still runs; your spreadsheet may not enjoy it.
- Types do not travel. CSV is text. Whatever reads the file next re-infers types, and an identifier such as 007 can come back as the number 7 in a careless reader. That is a property of CSV, not of this converter, and it is the main argument for keeping the Avro around.
- The preview is the first 20 rows. Everything else is in the file you download, and the row count beside the table tells you how many that is.
- Only null and deflate compressed files open. A snappy or zstandard container stops with the codec named in the message. Re-encode with your writer's codec set to deflate, or to none, and drop it again.
- A container with a non record schema still converts. A file written with a bare scalar schema comes back as a single column called value, one row per entry. It is a rare shape but it does not error.
Frequently Asked Questions
How are nested records turned into columns?
With dots. A record field called device holding os becomes a column called device.os, and that continues down through nested records to four dot separated parts. A branch deeper than four is written into one cell as JSON text, and the result panel adds a note saying how many places that happened in. Nothing is renamed and no prefix is invented.
What happens to array fields?
An array becomes JSON text inside a single cell, and an empty array becomes an empty cell. Rows are never multiplied behind your back, because one Avro record must stay one CSV row for the row counts to mean anything. When the array held records rather than scalars, the result says so in a note. If you want the array elements as real structure, convert to JSON instead and reshape there.
Is anything uploaded to a server?
No. The file is decoded and flattened by JavaScript running in your tab. There is no upload endpoint behind this page, no account, and no copy kept anywhere. The decoding library lives in a chunk of this site's own JavaScript, and the browser only asks for it once a file is sitting in the box, so landing here costs a page view and nothing more.
How large a file can it convert?
100 MB, with no row cap and no daily quota. A larger file is handed to the full editor, which streams the read instead. Keep in mind that the whole table is built in memory before the CSV is written, so a container packed with wide records will use more memory than its size on disk suggests.
Why do some columns only have values in some rows?
The column set is the union of every key seen across the records, in first seen order, so the first record decides the layout and anything new is appended on the right. A record that never mentions a key gets an empty cell there. Union fields and map keys are the usual cause, and an Avro null lands as an empty cell too, so a missing value and an explicit null look the same in CSV.
Can I pick which columns end up in the CSV?
Not on this page. The converter writes every field it finds, which is what you want when the point is to see the file. Drop the same .avro into the full editor if you need to select columns, filter rows or rename headers before exporting, and the pipeline there is recorded so the result can be reproduced.
Related
Turn your Avro into a table
Drop the .avro, check the columns in the preview, then copy the CSV or download it. Nothing uploads and there is no row cap.
Back to the converter