Swagger 2 to OpenAPI 3 Converter
Upgrade a Swagger 2.0 spec to OpenAPI 3.0 with every mapping shown — servers, requestBody, components — without the spec leaving this device.
Target: OpenAPI 3.0.3 — the ecosystem-converter norm; a 3.1 mode is not offered.
Remote $refs pass through unfetched — this page makes no network requests.
Press ? for shortcuts · Your spec is converted in a worker in this tab and never leaves this device.
Do it offline:$ npx swagger2openapi swagger.yaml -o openapi.yaml
How to use it
- Paste a Swagger 2.0 document — JSON or YAML — into the input pane, or open a .json/.yaml file up to 5 MB.
- Pick the output format (JSON or YAML) and choose how members with no 3.0 home are handled: annotated as x-oai2-* or stripped.
- Press Convert. The upgrade runs in a Web Worker on this device; nothing is uploaded.
- Read the change log: every applied rule is a row with its spec citation, and rows with a line number jump to that place in the output.
- Copy or download the OpenAPI 3.0.3 result. Share links carry the two options only — never your spec.
Paste a Swagger 2.0 definition and get the same API as an OpenAPI 3.0.3 document: host, basePath and schemes combine into servers, body and formData parameters become requestBody, definitions move under components, and security schemes remap to flows. Every applied rule lands in a change log with its spec citation. The conversion runs in a worker in this tab — your spec never leaves this device.
Examples
{
"swagger": "2.0",
"info": {
"title": "Orders API",
"version": "1.0.0"
},
"host": "api.example.com",
"schemes": [
"https"
],
"consumes": [
"application/json"
],
"paths": {
"/orders": {
"post": {
"parameters": [
{
"name": "order",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/Order"
}
}
],
"responses": {
"201": {
"description": "Created"
}
}
}
}
},
"definitions": {
"Order": {
"type": "object",
"properties": {
"id": {
"type": "string"
}
}
}
}
}{
"openapi": "3.0.3",
"info": {
"title": "Orders API",
"version": "1.0.0"
},
"servers": [
{
"url": "https://api.example.com"
}
],
"paths": {
"/orders": {
"post": {
"responses": {
"201": {
"description": "Created"
}
},
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Order"
}
}
},
"x-original-name": "order"
}
}
}
},
"components": {
"schemas": {
"Order": {
"type": "object",
"properties": {
"id": {
"type": "string"
}
}
}
}
}
}The body parameter becomes requestBody — its name has no 3.0 field, so it survives as x-original-name — and the definition moves to components/schemas with its $ref rewritten.
swagger: "2.0"
info:
title: Status API
version: "1.0"
host: status.example.com
basePath: /api
schemes:
- https
- http
paths:
/health:
get:
responses:
"200":
description: Healthy
openapi: 3.0.3
info:
title: Status API
version: "1.0"
servers:
- url: https://status.example.com/api
- url: http://status.example.com/api
paths:
/health:
get:
responses:
"200":
description: Healthy
host, basePath and both schemes combine into two servers, in scheme order — the cartesian rule. YAML in, YAML out.
swagger: "2.0"
info:
title: Import API
version: "2.0"
paths:
/import:
post:
consumes:
- multipart/form-data
parameters:
- name: file
in: formData
type: file
required: true
- name: mode
in: formData
type: string
enum:
- merge
- replace
responses:
"202":
description: Accepted
{
"openapi": "3.0.3",
"info": {
"title": "Import API",
"version": "2.0"
},
"paths": {
"/import": {
"post": {
"responses": {
"202": {
"description": "Accepted"
}
},
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"file": {
"type": "string",
"format": "binary"
},
"mode": {
"type": "string",
"enum": [
"merge",
"replace"
]
}
},
"required": [
"file"
]
}
}
},
"required": true
}
}
}
}
}Both formData parameters merge into one multipart/form-data schema and the file field becomes type: string, format: binary. The input was YAML — the output format is a setting, not an accident.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
The target is OpenAPI 3.0.3 — deliberately not 3.1
3.0.3 is what the ecosystem's converters emit and what nearly every generator and validator accepts. OpenAPI 3.1 realigns schemas with full JSON Schema — nullable, exclusiveMaximum and type arrays change meaning — so that upgrade is a semantic migration, not a bigger version digit. If a 3.1 target ships here it will be a new explicit option, never a silent change.
Remote $refs pass through unfetched
A $ref to https://… or to another file is left byte-identical and logged as a warning row. This page makes no network requests, so it cannot quietly inline remote documents — resolve them first (the CLI below can) if you need a self-contained result.
collectionFormat maps to style + explode — except tsv
For query parameters: csv becomes style: form with explode: false, multi becomes explode: true, ssv becomes spaceDelimited and pipes becomes pipeDelimited; path and header csv become simple. tsv has no OpenAPI 3.0 equivalent — it is kept as x-oai2-collectionFormat (or stripped) and warned about, never silently discarded.
Lossy corners are annotated, never silently dropped
A member with no 3.0 home — an unknown root member, a formData allowEmptyValue, a nested items collectionFormat — keeps its value under x-oai2-<name> in annotate mode; strip mode removes it but still logs the row. Either way the change log names what happened and cites the rule.
One body payload per operation — 2.0's own law, enforced
An operation with two body parameters, or a body parameter next to formData, was never legal Swagger 2.0. The converter refuses with the citation instead of guessing which payload wins — a wrong guess would change the API's meaning.
Common errors
The input is empty — paste a Swagger 2.0 document first.- Both panes need a document first. Load the sample to see the shape the converter expects, or drop a .json/.yaml file onto the input pane.
This document is already OpenAPI 3.0.0 — it has nothing to upgrade. This converter reads Swagger 2.0 (swagger: "2.0") only.- The version member at the root decides everything. An openapi: 3.x document is this tool's output, not its input — feeding a result back in refuses with exactly this message. A 3.x-to-2.0 downgrade is a different, lossy operation this page does not offer.
Operation POST /orders declares both a body parameter and formData parameters — Swagger 2.0 allows at most one body payload and forbids mixing body with formData (Swagger 2.0 — Parameter Object). Fix the source spec, then convert.- Swagger 2.0 itself forbids this combination, so there is no correct 3.0 translation to pick. Decide which payload the operation really takes, remove the other, and convert again.
Input is larger than the 5 MB limit for this tool. For bigger specs use the CLI: npx swagger2openapi swagger.yaml -o openapi.yaml- The cap keeps a worst-case parse-and-rewrite inside the 30-second worker budget. Specs beyond 5 MB belong to the CLI on your machine, which has no such limit.
FAQ
Why does this convert to OpenAPI 3.0 and not 3.1?
Because 3.0.3 is the safe landing zone: it is the target the ecosystem's converters emit and the version SDK generators and validators accept everywhere. OpenAPI 3.1 aligns schemas with full JSON Schema, which changes what nullable and type mean — a semantic migration, not a syntax move. If a 3.1 target is added it will be a separate explicit option; this page will not silently change its output.
Is my spec uploaded anywhere?
No. The conversion runs in a Web Worker in this tab and the page makes no network requests — unlike the widely used hosted converter at converter.swagger.io, which posts your document to a server. Share links carry the two options only; the spec itself is structurally absent from them.
What happens to $refs — local and remote?
Local references are rewritten to their new home: #/definitions/X becomes #/components/schemas/X, shared parameters move to components/parameters, and a referenced body parameter becomes a shared requestBody. Remote and file references pass through byte-identical with a warning row in the change log — they are never fetched.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Convert now.
- ⌘/Ctrl + S
- Download the result as .json or .yaml.
- ⌘/Ctrl + C
- Copy the result when nothing is selected.
- ⌘/Ctrl + Shift + C
- Copy the result even with a selection active.
- /
- Focus the Swagger 2.0 input.
- t
- Cycle the color theme.
- ? or ⌘/Ctrl + /
- Show the shortcut overlay.
- Esc
- Cancel a run, or dismiss a banner.