comparison

JSON schema vs grammar-constrained decoding: when JSON mode isn't enough for your language

the short answer

JSON mode and function-calling schemas constrain an LLM to a JSON shape with named fields and types, which is enough when your output really is JSON; for a custom DSL, query language, or config dialect that isn't JSON, you need a full grammar constraint instead, and dsl.ai compiles your grammar into exactly that so output is valid by construction in any language you can describe.

JSON mode and function calling are the structured-output features most people reach for first, and for good reason: they constrain a model to emit JSON that matches a schema, with the right keys, types, and required fields. If the thing you want out of the model is genuinely a JSON object, that's the right tool and you should stop there.

The gap shows up when your output isn't JSON. A custom DSL, a small query language, a route or alert syntax, a config dialect with its own punctuation — none of those are JSON objects, and bending them into one loses the structure that made them worth having. This page compares JSON-schema constraint with full grammar-constrained decoding so you can see exactly where the line falls.

any grammarconstrained, not only JSON-shaped output

What a JSON schema actually constrains

Under the hood, JSON mode works because the provider has the JSON grammar built in: the decoder is masked so the model can only emit tokens that keep the output a well-formed JSON value, and a schema layer narrows that further to your keys and types. It's a grammar constraint — just one fixed to a single grammar, JSON, that ships with the model.

That's why it's reliable for JSON and silent for everything else. The moment your target language has constructs JSON can't express — bare keywords, infix operators, indentation, a custom statement separator — a JSON schema can't describe them, so you're back to asking the model in a prompt and hoping the string parses.

When you need the full grammar

A full grammar-constrained decoder generalises the same idea to any language you can write down. You give dsl.ai your DSL's EBNF/GBNF-style grammar, it compiles that into the decoding mask, and at every step only tokens that keep the output inside your language survive. The guarantee is identical to JSON mode's — valid by construction — but the language is yours, not the provider's.

A common middle path is to wrap your DSL inside a JSON string field and use JSON mode for the envelope. That guarantees the envelope, not the DSL inside it: the string can still be malformed in your language. A grammar constraint covers the part JSON mode leaves unguarded, and the same grammar then drives a deterministic validator so you can prove any string is valid.

JSON-schema constraint vs grammar-constrained decoding

JSON mode / schemaGrammar-constrained (dsl.ai)
Languages coveredJSON shapes onlyAny language with a grammar
How it constrainsBuilt-in JSON grammar + schemaYour grammar compiled to a mask
Custom DSL / query syntaxNot expressibleExpressible and guaranteed
Validity guaranteeValid JSON by constructionValid in your language by construction
VerificationJSON schema validatorsDeterministic parser from the same grammar

frequently asked

Isn't JSON mode already a grammar constraint?
Yes — it constrains decoding to the JSON grammar specifically. Grammar-constrained decoding is the general case: you supply the grammar, so the same guarantee applies to your DSL or query language, not just JSON.
Can I just put my DSL in a JSON string field?
You can, and JSON mode will guarantee the envelope is valid JSON — but not that the DSL inside the string is valid. A grammar constraint covers the inner language; dsl.ai can constrain and validate it directly.
Does my model need to support function calling for this?
No. Grammar-constrained decoding works on any open model served through a runtime that accepts a GBNF-style grammar, independent of whether it offers JSON mode or function calling.
How do I verify the output is valid?
dsl.ai generates a deterministic parser from the same grammar, returning valid, or invalid at a specific position with what it expected — the equivalent of JSON schema validation, for your language.

Last updated June 8, 2026

ready to try dsl.ai?

open dslai