Skip to content

Latest commit

Β 

History

158 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

flatconfig

A minimal key = value configuration parser for Dart and Flutter.

Pub Version Tests License: MIT Dart Version Pub Points

Flat, human-friendly key = value configuration β€” inspired by πŸ‘» Ghostty, simpler than INI or TOML.

Configuration files people edit by hand should be boring to read and impossible to misread. flatconfig keeps the whole format at key = value: one flat namespace, no sections, no nesting, no parser magic. Every line means what it says.

It is built for tools, CLIs and Flutter apps that need structured settings without a heavy dependency β€” with duplicate keys, comments, explicit resets, recursive includes and lossless round-tripping.

Highlights

  • 🧩 Tiny syntax β€” key = value, quoted when it has to be
  • πŸ“¦ Pure Dart, two small dependencies (meta, and path for includes)
  • 🌍 Web and WASM safe, with file I/O in a library you simply do not import
  • πŸ“ Duplicate keys preserved, in order β€” which is how overriding works
  • πŸ” Strict or lenient, with one onIssue channel for every problem
  • βœ… Valid by construction β€” an entry the format cannot write out cannot be built
  • 🧠 One accessor rule β€” getX, getXOr, requireX, for every type
  • πŸ”Œ getAs for everything else β€” your converter, the same three shapes
  • πŸ” Round-trips, including the values that look like they should break it
  • πŸ“ Includes from disk, memory, assets or the network, through a resolver

Install

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

Which library to import

The package is four libraries. Each of the three below re-exports the core, so one import usually does.

Import Adds to the core Web / WASM
package:flatconfig/flatconfig.dart the core: documents, parsing, encoding, accessors βœ…
package:flatconfig/flatconfig_includes.dart following config-file through a resolver βœ…
package:flatconfig/flatconfig_accessors.dart DateTime, Duration, Uri, JSON, enum accessors βœ…
package:flatconfig/flatconfig_io.dart reading and writing files ❌ needs dart:io

Only flatconfig_io.dart touches dart:io, so a browser build simply does not import it. There is no stub that compiles and then throws at runtime.

Quick start

import 'package:flatconfig/flatconfig.dart';

void main() {
  const raw = '''
# Example configuration
background = 343028
foreground = f3d735
shader = bloom
shader = vignette
texture =
''';

  final doc = FlatDocument.parse(raw);

  print(doc['background']);         // 343028
  print(doc['shader']);             // vignette β€” the last write wins
  print(doc.allValues('shader'));   // [bloom, vignette]
  print(doc['texture']);            // null
  print(doc.lookup('texture'));     // FlatLookup.reset() β€” cleared on purpose
}

Typed reads follow one rule: getX returns null, getXOr returns your fallback, requireX throws.

final port     = doc.getIntOr('port', 8080);
final gamma    = doc.requireDouble('gamma');
final features = doc.getList('features');            // "a, b, c" β†’ [a, b, c]
final accent   = doc.getAs('accent', parseMyColor);  // anything else

Files hang off File, so a path is spelled the way it is everywhere else in Dart:

import 'dart:io';
import 'package:flatconfig/flatconfig_io.dart';

final doc = await File('main.conf').parseWithIncludes();
await File('out.conf').writeFlat(doc.withValue('font-size', '16'));

The format in one screen

# Comments start with "#" and take a whole line.
# Whitespace around "=" is ignored.

background = 343028
# Quotes preserve spaces, "=" and "#". They are not inline comments:
# this format has whole-line comments only.
font-family = "FiraCode Nerd Font"

# A key may appear more than once. The last one wins,
# and every value stays readable through allValues().
shader = bloom
shader = vignette

# An empty value is an explicit reset, not an empty string.
texture =
empty = ""

# Pull in another file. Later includes win; "?" marks it optional.
config-file = theme.conf
config-file = ?user.conf

Keys are case-sensitive. The comment prefix is configurable; the = separator is not. SPEC.md is the normative definition, and its Appendix A tracks where the implementation still deviates from it.

Compared to INI and TOML

Feature INI / TOML flatconfig
Sections / tables βœ… [section] 🚫 one flat namespace
Nested data βœ… tables or dotted keys 🚫 flat, but fromData flattens for you
Comments # or ; # only, whole-line
Lists βœ… [1, 2, 3] βœ… getList(), or repeat the key
Types explicit strings plus typed accessors
Includes ❌ (TOML: preprocessors only) βœ… built in, recursive, pluggable
Duplicate keys ❌ usually an error βœ… the mechanism for overriding

Leaving out sections is the point rather than a shortcut: a single flat namespace makes merging, overriding and diffing trivial, and keeps the files readable for people who do not write code.

Think of it as the portable 20% of INI that covers 90% of real configuration.

Documentation

Page What is in it
Parsing entry points, options, strict vs lenient, reporting problems
The document model entries and the resolved view, the three states, editing, collapse, prefixes
Accessors the three shapes, custom converters, the optional accessors
Includes config-file, merge policies, writing a resolver
Building documents from maps, the environment and nested data; encoding and round-tripping
Files and platforms the File API, and what runs on the web
Migrating from 0.5.x the complete rename and removal table
Working on flatconfig tests, coverage, CI, house rules
SPEC.md the format, normatively

Runnable examples live in example/, including a Flutter app in example/flatconfig_flutter.

Design philosophy

Flat, simple, predictable. No nested scopes, no hidden semantics, no parser magic. The goal is not to replace JSON, YAML or TOML, but to be the lightweight middle ground: friendly enough to hand-edit, strict enough to automate.

Where that forces a choice, it is resolved towards the reader of the file. A malformed line is reported rather than swallowed, a value that cannot survive a round trip is refused when it is written rather than mangled when it is read, and a key that was cleared on purpose is distinguishable from one nobody ever mentioned.

flatconfig keeps your config files boring β€” in the best possible way. 😌

See also

License

MIT


Made with ❀️ in Dart β€” grumpypixel/flatconfig

About

Flat, human-friendly key=value config format for Dart & Flutter β€” inspired by πŸ‘» Ghostty.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages