We use tons of configuration at work and this has come up time and time again. The biggest pain is when inevitably you need to "parameterize" your JSON files. The most common route I've seen is to turn your configs into templates e.g. Jinja and go from there. Welcome to hell.

My solution? Write a DSL with Typescript, and "compile" your configs down to JSON.

Define the structure of your configs as TS types. Write functions with free variables to work as templates, or define snippets as composable fragments. Writing the end result to a JSON file results in transparency (what you see is what you get) and compatibility.

jsonnet[1] might suit your use-case better, it was created to do exactly that.

[1]https://jsonnet.org

jsonnet is my go-to language for anything related to configuration, after having tried json, yaml, TS, edn, and tasting dhall and toml. It addresses all problems in the article and more.

the composition model strikes a good balance between data extensibility / language expressiveness / ease of use.

the generated json leads to easy-to-understand and portable data, and if you write jsonschemas from jsonnet, tools like json-schema-to-typescript [1] make it easy to import a consistent interface, and almost every language has a reasonably up-to-date validation library.

[1] https://github.com/bcherny/json-schema-to-typescript