OpenAPI 3.1 vs 3.0: what actually changed
OpenAPI 3.1 looks like a minor bump but is the biggest schema change in the specification's history: the Schema Object became a full JSON Schema 2020-12 vocabulary instead of a modified subset. The differences that bite in practice:
The changes that matter
| Topic | OpenAPI 3.0 | OpenAPI 3.1 |
|---|---|---|
| Nullable values | type: string + nullable: true | type: [string, "null"] — nullable is gone |
| Exclusive bounds | exclusiveMinimum: true (boolean modifier) | exclusiveMinimum: 5 (a number itself) |
| JSON Schema keywords | Subset (const, if/then… unavailable) | Full 2020-12: const, prefixItems, patternProperties, conditionals |
| Webhooks | — | Top-level webhooks for calls your API makes out |
| Root requirements | paths required | Any of paths, components or webhooks suffices |
| License | url | identifier (SPDX) as an alternative |
Migration gotchas
Tools that "support 3.1" sometimes just relax validation. The classic mistakes when bumping the
version line: leaving nullable in place (ignored in 3.1), keeping boolean
exclusiveMinimum, and assuming every renderer understands 2020-12 keywords.
This is exactly what a version-aware validator is for: OASForge lints the document against the
rules of its declared version — nullable in a 3.1 file gets a warning with
the type-array replacement, a 3.1-only keyword in a 3.0 file offers a one-click version bump, and
the exclusive-bounds shape is checked both ways. Try it by pasting your spec into the
editor.
No signup, no install — the editor runs entirely in your browser.
Start in the editor