wireform-toml
wireform-toml reads and writes TOML configuration for Haskell services and
tools. TOML’s table sections, inline tables, and array-of-tables map naturally
onto Haskell records when you derive Generic, while the encoder places
[section] headers and [parent.child] paths correctly on output. The parser
is validated against the upstream toml-test
suite for both TOML 1.0 and 1.1.
Key features
Section titled “Key features”| Capability | Why it matters |
|---|---|
deriveTOML Template Haskell deriver | Load config files into typed records with wireform-derive annotations; Generic defaults work for simple cases |
| Section-aware pretty printing | [database] and nested [database.pool] headers land in sensible order |
| Datetime support | RFC 3339 offsets and local datetimes as first-class values |
| Inline and standard tables | Compact inline { key = "val" } or full [table] blocks |
| Array-of-tables | [[items]] repeated sections for list-of-struct configs |
| toml-test conformance | Confidence that edge cases match the spec |
Basic usage
Section titled “Basic usage”Typed configuration
Section titled “Typed configuration”Derive codecs with the Template Haskell deriver and round-trip with
encodeTOML / decodeTOML.
{-# LANGUAGE DeriveGeneric #-}{-# LANGUAGE TemplateHaskell #-}{-# LANGUAGE OverloadedStrings #-}import GHC.Generics (Generic)import Data.Text (Text)import TOML.Class (ToTOML, FromTOML, encodeTOML, decodeTOML)import TOML.Derive (deriveTOML)
data Database = Database { dbHost :: !Text , dbPort :: !Int } deriving stock (Generic)
data AppConfig = AppConfig { appName :: !Text , database :: !Database } deriving stock (Generic)
$(deriveTOML ''Database)$(deriveTOML ''AppConfig)
loadConfig :: Text -> Either String AppConfigloadConfig = decodeTOMLFor simple cases with no wire-format customization, Generic defaults also
work: add deriving Generic and declare empty instance ToTOML Database and
instance FromTOML Database declarations (and likewise for AppConfig).
Nested records become TOML subtables. The encoder emits a [database] section
with keys under it rather than flattening everything at the top level.
Datetimes
Section titled “Datetimes”TOML datetimes live in TOML.Value as TLocalDateTime, TOffsetDateTime, and
related constructors. Deriving handles them when fields use the corresponding
Haskell types from the value module.
{-# LANGUAGE DeriveGeneric #-}{-# LANGUAGE TemplateHaskell #-}{-# LANGUAGE OverloadedStrings #-}import GHC.Generics (Generic)import Data.Text (Text)import TOML.Class (FromTOML, decodeTOML)import TOML.Derive (deriveTOML)
data Job = Job { jobName :: !Text , scheduledAt :: !Text } deriving stock (Generic)
$(deriveTOML ''Job)
parseJob :: Text -> Either String JobparseJob = decodeTOMLTOML datetimes decode as Text in the value layer (TDateTime, TDate,
TTime). Map them into time types in application code when you need calendar
arithmetic.
Direct encoding for large configs
Section titled “Direct encoding for large configs”encodeTOMLDirect routes through toEncoding when you want the same path the
TH deriver uses, which can avoid an extra conversion for complex nested values.
import TOML.Class (ToTOML, encodeTOMLDirect)
writeConfig :: ToTOML a => a -> TextwriteConfig = encodeTOMLDirectUse TOML.Decode.decode on raw text when you need the untyped TOML.Value
AST before mapping into application types.
Performance
Section titled “Performance”Encode/decode
Section titled “Encode/decode”| Operation | encode | decode | ratio |
|---|---|---|---|
| single Person | 730 ns | 2383 ns | 3.26x |
| [Person] x 100 | 86012 ns | 343876 ns | 3.100x |
Last run 2026-06-27 11:35:55 UTC. ghc-9.8.4 on darwin-aarch64, criterion 1.6.5. Decode is now linear in input size (was previously O(N²) due to T.index/T.length on the full source); 100-record decode dropped from 240 ms to 335 µs..
Decode scales linearly with input size.
The chart and table above are regenerated by wireform-stats from wireform-toml/bench-results/summary/toml-encode-decode.json — the same source the README chart is built from.
Notable modules
Section titled “Notable modules”| Module | Role |
|---|---|
TOML.Class | ToTOML / FromTOML, encodeTOML, decodeTOML |
TOML.Value | AST for tables, arrays, datetimes, and inline tables |
TOML.Encode | Section-aware TOML writer |
TOML.Decode | Parser for TOML 1.0 / 1.1 documents |
TOML.Encoding | Intermediate encoding type used by the deriver |
TOML.Derive | Template Haskell deriver with Wireform.Derive annotations |