csv_plus v1.2.0
pub.dev GitHub

How to parse a CSV string in Dart

Turn CSV text into rows, with the awkward parts of the format handled for you.

Install#

dart pub add csv_plus
import 'package:csv_plus/csv_plus.dart';

Decode a string#

import 'package:csv_plus/csv_plus.dart';

void main() {
  final codec = CsvCodec();
  final rows = codec.decode('name,age\nAlice,30\nBob,25');

  for (final row in rows) {
    print(row);
  }
  // [name, age]
  // [Alice, 30]
  // [Bob, 25]
}

Values come back typed. 30 is an int, not the string "30". See type inference for how that is decided and how to override it.

The parts of CSV that usually break parsers#

A field wrapped in quotes may contain the delimiter, a line break, or an escaped quote. All three are handled:

final rows = codec.decode('name,note\n"Smith, Alice","said ""hello""\nand left"');

rows[1][0]; // Smith, Alice
rows[1][1]; // said "hello"
            // and left

That second field contains a real newline and still belongs to one row, which is why splitting CSV on \n yourself goes wrong on real exports.

Malformed input#

By default the parser recovers from damage and gives you what it can. When you would rather know, turn on strict mode:

final strict = CsvCodec(CsvConfig(strict: true));
strict.decode('"unterminated'); // throws CsvParseException

There is a lenient decoder too, for input you know is untidy:

codec.decodeFlexible('  a , b '); // trims, recovers bad quotes

Skipping a preamble#

Exports often start with comment lines or a title block before the real header.

final codec = CsvCodec(CsvConfig(comment: '#', hasHeader: true));

codec.decode('# export 2026-07-17\nname,score\nAlice,95');
// [[Alice, 95]]

comment only matches at the start of a line, so a # inside a quoted value stays content. skipRows drops leading rows before the header is read, and maxRows caps how many data rows you load.