The Big Picture
OpenAPI 3.1, released in February 2021, was the first major version update since 3.0 landed in 2017. The headline change — full alignment with JSON Schema (draft 2020-12) — sounds incremental. In practice, it touched nearly every corner of the specification and introduced subtle breaking changes that catch teams off guard during migration.
This article covers every significant difference, explains why each change was made, and gives practical migration guidance.
What Changed: The Complete Breakdown
Full JSON Schema Compatibility
This is the change that motivated the entire 3.1 release.
In OpenAPI 3.0, the Schema Object was a superset of JSON Schema Draft 4 with OpenAPI-specific extensions. This meant that standard JSON Schema validators rejected OpenAPI schemas, and OpenAPI validators had to implement custom logic for keywords like nullable.
OpenAPI 3.1 adopts JSON Schema draft 2020-12 without modifications. A schema that validates in JSON Schema now validates in OpenAPI, and vice versa.
Practical impact:
# OpenAPI 3.0 — nullable required a special keyword
type: string
nullable: true
# OpenAPI 3.1 — uses standard JSON Schema
type:
- string
- "null"
The nullable keyword is removed entirely. If your tooling generates nullable: true, it will be ignored in 3.1 — silently, in most cases.
Webhooks as a Top-Level Object
OpenAPI 3.0 had no native way to describe webhooks. Teams either abused callbacks or documented webhooks outside the spec entirely.
3.1 adds a webhooks object at the root level:
webhooks:
orderCompleted:
post:
summary: Order completed notification
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/OrderEvent'
responses:
'200':
description: Webhook received
This is a significant improvement for event-driven APIs, which are increasingly the norm.
type Can Be an Array
One of the most visible changes for schema authors. In 3.0, type was always a string. In 3.1, it can be an array:
# 3.0
type: string
# 3.1 — field accepts string or integer
type:
- string
- integer
This replaces the oneOf workaround that was previously necessary for union types, making schemas shorter and easier to read.
New Keywords from JSON Schema
OpenAPI 3.1 inherits several useful keywords that were previously unavailable:
if/then/else— Conditional schemasdependentRequired— Field X is required only when field Y is presentprefixItems— Replaces the tuple form ofitems$dynamicRef— Advanced recursive schema references
exclusiveMinimum and exclusiveMaximum Are Now Numbers
In JSON Schema Draft 4 (used by 3.0), these were booleans. In draft 2020-12 (used by 3.1), they are numbers:
# 3.0
minimum: 0
exclusiveMinimum: true
# 3.1
exclusiveMinimum: 0
This is a silent breaking change. Your 3.0 schemas will parse without errors in most 3.1 tools — but the semantics will be wrong.
example vs examples
In 3.0, the Schema Object had an example keyword (singular). In 3.1, JSON Schema's examples keyword (plural, an array) is preferred:
# 3.0
example: "john@example.com"
# 3.1
examples:
- "john@example.com"
- "jane@example.com"
The singular example still works for backward compatibility, but examples is the recommended path forward.
Complete Comparison Table
| Feature | OpenAPI 3.0 | OpenAPI 3.1 |
|---|---|---|
| JSON Schema version | Draft 4 (modified) | Draft 2020-12 (unmodified) |
nullable keyword |
Supported | Removed — use type: [string, "null"] |
type as array |
Not supported | Supported |
| Webhooks | Not supported natively | Top-level webhooks object |
exclusiveMinimum |
Boolean | Number |
example keyword |
Singular only | Singular + plural examples array |
if/then/else |
Not available | Available |
$ref with siblings |
Not allowed | Allowed |
discriminator |
Available | Available (unchanged) |
pathItems in webhooks |
N/A | Reuses Path Item Object |
Breaking Changes to Watch For
1. The nullable removal
This is the most common migration issue. Every schema that uses nullable: true needs to be rewritten to use type arrays. In a large API, this can affect hundreds of fields.
2. Boolean exclusiveMinimum / exclusiveMaximum
These will silently produce incorrect validation results, not errors. Test thoroughly.
3. Tooling support
Not all tools support 3.1 yet — or they support it partially. Before migrating, verify that your code generators, validators, and documentation renderers handle 3.1 correctly.
Migration Tips
- Audit your
nullableusage first. This is the highest-volume change. Write a script to find and replace. - Update your toolchain before your spec. Ensure every tool in your pipeline handles 3.1.
- Migrate incrementally. Move one service at a time, not your entire API surface at once.
- Run both validators. During migration, validate against both 3.0 and 3.1 to catch regressions.
- Use Specway's auto-detection. When you import a spec into Specway, it detects the OpenAPI version automatically and renders correctly for both 3.0 and 3.1.
Should You Migrate?
If you are starting a new API — yes, use 3.1. There is no reason to start on 3.0 in 2026.
If you have an existing 3.0 spec — migrate when your toolchain is ready and when you have a concrete need (webhooks, JSON Schema alignment, or union types). A forced migration for its own sake rarely justifies the testing overhead.
Conclusion
OpenAPI 3.1 is a meaningful step forward, primarily because it eliminates the gap between JSON Schema and OpenAPI schemas. The migration is worth doing, but it is not trivial — particularly the nullable removal and the exclusiveMinimum change, which can break validation silently. Plan for it, test it, and migrate on your own timeline.