Skip to content

# CSV (Comma Separated Values)

Glaze supports CSV reading and writing for structs and standard map types.

By default Glaze writes out structures row-wise, which is more efficient if all the data is available at once. Column-wise CSV format is also supported.

> Note that if you want containers to have their CSV data aligned, they need to be the same length.

## API

    glz::read_csv(obj, buffer); // row-wise
    glz::read_csv<glz::colwise>(obj, buffer); // column-wise

    glz::write_csv(obj, buffer); // row-wise
    glz::write_csv<glz::colwise>(obj, buffer); // column-wise

## Example

    struct my_struct
    {
       std::vector<int> num1{};
       std::deque<float> num2{};
       std::vector<bool> maybe{};
       std::vector<std::array<int, 3>> v3s{};
    };

Reading/Writing column-wise:

    std::string input_col =
           R"(num1,num2,maybe,v3s[0],v3s[1],v3s[2]
    11,22,1,1,1,1
    33,44,1,2,2,2
    55,66,0,3,3,3
    77,88,0,4,4,4)";

        my_struct obj{};

        expect(!glz::read_csv<glz::colwise>(obj, input_col));

        expect(obj.num1[0] == 11);
        expect(obj.num2[2] == 66);
        expect(obj.maybe[3] == false);
        expect(obj.v3s[0] == std::array{1, 1, 1});
        expect(obj.v3s[1] == std::array{2, 2, 2});
        expect(obj.v3s[2] == std::array{3, 3, 3});
        expect(obj.v3s[3] == std::array{4, 4, 4});

        std::string out{};

        expect(!glz::write<glz::opts{.format = glz::csv, .layout = glz::colwise}>(obj, out));
        expect(out ==
               R"(num1,num2,maybe,v3s[0],v3s[1],v3s[2]
    11,22,1,1,1,1
    33,44,1,2,2,2
    55,66,0,3,3,3
    77,88,0,4,4,4
    )");

        expect(!glz::write_file_csv<glz::colwise>(obj, "csv_test_colwise.csv", std::string{}));

## Headerless CSV for Struct Vectors

You can read and write vectors of structs without headers by disabling headers in `opts_csv`.

    struct data_point { int id; float value; std::string name; };

    std::vector<data_point> vec = {
      {1, 10.5f, "Point A"},
      {2, 20.3f, "Point B"}
    };

    std::string out;
    glz::write<glz::opts_csv{.use_headers = false}>(vec, out);
    // out:
    // 1,10.5,Point A\n
    // 2,20.3,Point B\n

    std::vector<data_point> back;
    glz::read<glz::opts_csv{.use_headers = false}>(back, out);

Notes: - Fields are in declaration order when `use_headers = false`. - You can also parse CSV that contains a header row by skipping it:

    glz::read<glz::opts_csv{
      .use_headers = false,
      .skip_header_row = true
    }>(back, headered_csv_string);

## 2D Arrays (matrix-style CSV)

Glaze supports reading and writing 2D arrays such as `std::vector<std::vector<T>>`:

Row-wise (default):

    std::string csv = "1,2,3\n4,5,6\n";
    std::vector<std::vector<int>> m;
    glz::read<glz::opts_csv{.use_headers = false}>(m, csv);
    // m == {{1,2,3},{4,5,6}}

    std::string out2;
    glz::write<glz::opts_csv{.use_headers = false}>(m, out2);

Column-wise (transpose on IO):

    std::vector<std::vector<int>> cols = {{1,4},{2,5},{3,6}}; // 3 columns
    std::string out;
    glz::write<glz::opts_csv{.layout = glz::colwise, .use_headers = false}>(cols, out);
    // out is row-wise CSV: 1,2,3\n4,5,6\n

    std::vector<std::vector<int>> back;
    glz::read<glz::opts_csv{.layout = glz::colwise, .use_headers = false}>(back, out);
    // back == cols

Options: - `skip_header_row` — skip the first row when reading (useful when ingesting headered CSV into 2D arrays without using headers). - `validate_rectangular` — enforce equal column counts across rows on read. - On failure, `read` returns `constraint_violated` and sets a message in `ctx.custom_error_message`.

## CSV Quoting and Special Values

- Strings and chars are quoted when needed; embedded quotes are escaped by doubling them.
- Quoted fields preserve commas, quotes, and newlines (handles both `\n` and `\r\n`).
- Empty fields are parsed as default values (e.g., `0` for numbers, empty string for strings, `false` for booleans).
- Booleans accept `true`/`false` (case-insensitive) and `0`/`1`; empty boolean fields default to `false`.

Examples:

    std::vector<std::string> row = {"Normal", "Has,comma", "Has \"quotes\"", "Multi\nline"};
    std::vector<std::vector<std::string>> m = {row};
    std::string out;
    glz::write<glz::opts_csv{.use_headers = false}>(m, out);
    // out contains properly quoted and escaped CSV

    std::vector<std::vector<std::string>> back;
    glz::read<glz::opts_csv{.use_headers = false}>(back, out);

## Choosing the Options API

For CSV, prefer `opts_csv` to access CSV-specific options:

    glz::write<glz::opts_csv{.layout = glz::colwise, .use_headers = false}>(obj, out);
    glz::read<glz::opts_csv{.use_headers = false, .skip_header_row = true}>(obj, in);

The helper convenience functions (`read_csv`, `write_csv`) remain available for basic cases.