Reference

OpenAPI 3.1 vs Swagger 2.0: should you upgrade first?

If you're still on Swagger 2.0, upgrade straight to OpenAPI 3.1 — do not stop at 3.0 first. The only reason to land on 3.0 instead is a specific tool in your pipeline (a codegen plugin, a legacy gateway import) that reads 3.0 but not 3.1 yet, and that's a tool problem with a fix date, not a spec preference. This page is the decision table for that call, built from the actual differences between the two spec texts, not from a generic "which version is newer" take.

We already cover OpenAPI 3.1 vs 3.0 and what Swagger vs OpenAPI even means as separate questions. This page answers the one teams starting from Swagger 2.0 actually have: do you need the 3.0 stop at all.

What actually changes between Swagger 2.0 and OpenAPI 3.1?

Everything that changed 2.0→3.0 plus everything that changed 3.0→3.1 — there is no shortcut that skips the 2.0→3.0 structural rewrite. Per the Swagger 2.0 specification text, a 2.0 document requires exactly three top-level fields — swagger, info, paths — and stores reusable schemas in a flat root-level definitions object. It has no components, no servers array (only a single host + basePath + schemes), and no oneOf/anyOf — only allOf composition is defined. Global request/response media types are declared with consumes/produces arrays instead of per-content-type schemas.

OpenAPI 3.1 replaces all of that: definitions becomes components/schemas, host/basePath/schemes become a servers array (so you can list more than one base URL), consumes/produces are gone in favor of a content map keyed by media type, and the Schema Object itself is now real JSON Schema 2020-12 — so oneOf, anyOf, type: [string, "null"], and a top-level webhooks: block all become available. None of that is optional or additive on top of a 2.0 file; every path object, every schema, and every security definition gets rewritten in the move to 3.x. 3.1 does not add a second rewrite on top of 3.0 — it adds five specific differences (detailed in our 3.0-vs-3.1 breakdown) on top of the same 3.x structure 3.0 already uses.

Should you go to 3.0 or straight to 3.1? (decision table)

Go straight to 3.1 unless a specific tool in your pipeline still reads only 3.0.

Question Go straight to 3.1 Stop at 3.0 first
Starting a brand-new spec from scratch? Yes — always No reason to
Migrating an existing Swagger 2.0 file? Yes, in one pass Only if step 2 below fails
Does your codegen/validator/docs tool read 3.1 today? Confirm this first — most do in 2026 If it only reads 3.0, fix or replace the tool before deciding spec version
Do you need webhooks (webhooks:), oneOf/anyOf, or nullable unions? 3.1 is the only version with these 3.0 cannot express them at all
Is a partner or gateway hard-coded to accept only 3.0? Generate 3.1 as source, downgrade a 3.0 copy for that one consumer Don't make 3.0 your source of truth just for one consumer

The rule the table reduces to: 3.0 is never the destination, only a possible intermediate stop forced by a specific tool. If nothing in your pipeline is 3.0-only, there's no version of "stop at 3.0 to be safe" that buys you anything — you'd be doing the same definitions:components: rewrite twice.

Why not land on 3.0 "to be safe"?

Because 3.0 and 3.1 are structurally identical outside five isolated differences, so 3.0 buys you no extra tool compatibility beyond what those five differences touch. The five 3.0-vs-3.1 gaps are: nullable: true vs type: [x, "null"], boolean vs numeric exclusiveMinimum/exclusiveMaximum, top-level webhooks: (3.1 only), JSON Schema 2020-12 example semantics, and the schema dialect keyword. If your Swagger 2.0 migration doesn't hit any of those five, going to 3.0 or 3.1 is the same amount of work with the same result on every other field — paths, components/definitions, security, tags, operationId. You'd only be choosing to also carry forward 3.0's flatter, less expressive schema model for no compatibility gain.

When is 3.0 the right place to stop?

Only when a specific, named tool in your critical path is verified 3.0-only. Test this directly rather than assuming: run your OpenAPI file through the tool. If it silently drops oneOf, chokes on type: [string, "null"], or rejects the openapi: 3.1.0 version string outright, that's your answer — and the fix is to track that tool's own 3.1 support (most actively maintained OpenAPI tools added it years ago) rather than to standardize your source spec on 3.0. Generate 3.1 as your source of truth and produce a 3.0 copy only for that one consumer, the same way our downgrade walkthrough treats a 3.0 file as a generated artifact, not a hand-maintained one.

What should you do this week?

  1. Run your current Swagger 2.0 file through the free in-browser OpenAPI validator after conversion — it flags structural issues in both 3.0 and 3.1 documents before you commit to either.
  2. Use the Swagger 2.0 to OpenAPI 3 converter to produce a 3.x draft, then hand-apply the 3.1-specific fields (webhooks:, type: [x, "null"] for any nullable field, numeric exclusiveMinimum) rather than stopping at the converter's 3.0 output.
  3. Test your actual codegen and docs tools against a small 3.1 sample before deciding anything based on their marketing copy — tool support pages lag behind reality in both directions.

If you want a 3.1 spec generated and SDK/docs previews built from your existing Swagger 2.0 file in one pass, Sourced reads 2.0, 3.0, and 3.1 — start a free report and see the converted spec plus generated SDK/docs previews before anything ships.