English

Developer tools · Syntax converters

Migrating a JSON config to TOML: what converts and what needs a human

· Why it matters

json toml developer-workflow

JSON values moving into TOML while null values are flagged and removed
Original ToolAcre vector illustration

TOML has become the config format for Python and Rust projects, and many JSON settings files are moving to it. This post explains which parts convert mechanically and which (null, mixed arrays, deep nesting) require judgement.

The setup.cfg and settings.json era is ending — a project consolidating configuration into pyproject.toml and the JSON blocks that need to move

Projects sometimes consolidate settings into one TOML file, but the repository cannot support the outline’s claim that an “era is ending.” The practical task is narrower: move a JSON-shaped object into a TOML table, inspect losses, then verify that the target application actually recognizes the resulting keys.

ToolAcre requires a root object for TOML output. A root array, string, number, Boolean or null is refused because a TOML document is a table. That early shape check prevents an invented wrapper from looking like application-approved configuration.

A configuration consolidation is a project choice, not a universal end of older formats

The converter proves concrete mechanics: TOML has tables, arrays and scalar values; its writer turns nested objects into valid TOML structures. It also has no null and uses a syntax different from JSON braces. Claims about ecosystem preference or design superiority require sources outside these implementation files.

Comments are one reason maintainers may prefer authored TOML, yet JSON input contains none to carry across. The generated document is a starting value serialization. Human explanation and project-specific organization must be added afterward.

What this converter proves about TOML rather than general format advocacy

Strings, finite numbers, booleans, nested objects and arrays supported by smol-toml convert mechanically. Arrays of objects can become arrays of tables; nested objects can become table headers. Unicode and escaped newlines survive tested round trips for ordinary values.

TOML array rules can reject shapes its writer cannot express, and the error names that failure rather than coercing silently. Calling all arrays homogeneous in advance would oversimplify the dependency’s tested behaviour, which even reads heterogeneous arrays. Use actual conversion as the gate.

What converts mechanically, including arrays the TOML writer accepts

Null has no TOML representation. Object properties holding null are omitted and listed in a warning. A null inside an array becomes an empty string so later indices do not shift; that replacement is also named. Neither outcome preserves the original value.

Decide what null meant before accepting either change. It may mean inherit a default, explicitly clear a field or no value supplied. Deleting the key or substituting empty text can alter application semantics, so resolve it against the destination’s documented configuration model.

Where style needs a human — choosing between [table] headers, dotted keys and inline tables, and grouping related keys so the file reads well

The tree does not say whether maintainers prefer `[tool.linter]`, dotted keys or inline tables. A serializer chooses valid syntax, while a human chooses grouping that makes ownership and related options clear. Sorting keys can make output deterministic but may separate concepts that belong together.

Preserve a small diff and add comments after values are verified. Converting TOML back to JSON later cannot restore those comments or the chosen table spelling. Style is authored information outside the plain value model.

Worked example: a linter's JSON config to TOML — converting, resolving two null values and regrouping the result under a [tool.linter] header

Convert `{"tool":{"linter":{"lineLength":100,"preview":null,"exclude":["dist",null]}}}`. The root object is accepted. `preview` is omitted; the null array member becomes an empty string; warnings name both paths. The remaining nested object is serialized under TOML tables chosen by the writer.

Before saving, decide whether preview should be false, absent or another documented value, and whether an empty exclude entry is valid. Then regroup and comment the table for readers. The example demonstrates why conversion is mechanical while migration is semantic.

What this does not cover — whether the target tool actually reads TOML, and its specific key names, which only its documentation can tell you

A valid TOML file does not prove that a tool reads TOML, recognizes the section or interprets the keys like the old JSON consumer. Check current target documentation and run its own validation or dry-run command. ToolAcre never imports an application schema.

Dates also deserve care in the reverse direction. TOML-native temporal values become strings when read into JSON, so a later round trip quotes them. A migration chain crossing both directions cannot be called lossless.

Takeaway: convert first, then edit for readability — and how the Syntax converters panel does the mechanical part in your browser

Convert first to expose mechanical incompatibilities, then edit for semantics and readability. Keep the original, review every warning and test with the actual target. Null handling and root shape are hard boundaries; table organization is a human design decision.

Syntax converters removes repetitive syntax work without inventing application knowledge. That division makes the output useful: machine-produced structure for review, followed by deliberate choices where the formats or tools disagree.

Keep a migration note for every warning you accept. If a null becomes absence, state the destination default that makes absence correct. If a null array member becomes empty text, explain why the index matters and why empty text is valid. If the writer rejects a mixed array, redesign that value instead of coercing it privately. These decisions are the durable migration record; the generated TOML alone cannot explain them to the next maintainer.