Frameworks

Generate an SDK from .NET with Swashbuckle or Microsoft.AspNetCore.OpenApi

ASP.NET Core has two real paths to an OpenAPI spec. Swashbuckle.AspNetCore is the long-standing third-party package, with its own Swagger UI. Since .NET 9, Microsoft.AspNetCore.OpenApi is built in — no third-party dependency for the spec itself, though it ships no UI of its own. Either way, a .NET OpenAPI SDK is the same two-step problem as any other framework: get a clean spec out, then run it through a generator or a hosted pipeline like Sourced.

Option 1: Swashbuckle.AspNetCore

dotnet add package Swashbuckle.AspNetCore
builder.Services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
});

// ...

app.UseSwagger();
app.UseSwaggerUI(options =>
{
    options.SwaggerEndpoint("v1/swagger.json", "My API V1");
});

The spec is served at /swagger/v1/swagger.json, with an interactive UI mounted alongside it. As of Swashbuckle.AspNetCore's current 10.x major version, it can emit OpenAPI 3.1, 3.0, or Swagger 2.0 documents — 3.1 support arrived in v10.0 via an upgrade to Microsoft.OpenApi 2.x, so pin your major version deliberately if a downstream tool needs a specific spec version. Swashbuckle.AspNetCore supports ASP.NET Core 8.0 and later.

Option 2: the built-in Microsoft.AspNetCore.OpenApi (.NET 9+)

Starting with .NET 9, ASP.NET Core includes OpenAPI document generation without a third-party package:

dotnet add package Microsoft.AspNetCore.OpenApi
builder.Services.AddOpenApi();

// ...

app.MapOpenApi();

That's the whole setup. The document is served at /openapi/v1.json by default (/openapi/{documentName}.json, where the document name defaults to v1); appending .yaml to the MapOpenApi route gets you YAML instead. The one thing it doesn't give you: a UI. Microsoft's own docs are explicit that "exposing the generated OpenAPI definition via a visual UI requires a third-party package" — Swagger UI, Scalar, or similar, wired up separately.

The gotcha: the default OpenAPI version depends on your .NET version

This one is easy to get wrong because it's silent. With Microsoft.AspNetCore.OpenApi on .NET 9, the default generated document is OpenAPI 3.0. Starting with .NET 10, the default flips to OpenAPI 3.1. If you upgrade your app's target framework without checking, the spec version your pipeline receives can change under you. To pin it explicitly regardless of .NET version:

builder.Services.AddOpenApi(options =>
{
    options.OpenApiVersion = Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_0;
});

Sourced, like most SDK and docs tooling, accepts OpenAPI 3.0 and 3.1 input — so either default works — but validate what you're actually emitting before assuming. See OpenAPI 3.1 vs 3.0 for what the difference means downstream.

The gotcha: operationId is omitted by default, on both packages

Swashbuckle.AspNetCore's own docs state this plainly: "Swashbuckle.AspNetCore omits the operationId by default," because auto-generating one that's both unique and meaningful in a client library is non-trivial. The fix is a Name on the route, or a custom strategy:

[HttpGet("{id}", Name = "GetProductById")]
public IActionResult Get(int id) { /* ... */ }

Minimal APIs on Microsoft.AspNetCore.OpenApi have the same gap: without .WithName(...) or an explicit OperationId set via .WithOpenApi(...), no operation ID is emitted for that endpoint.

app.MapGet("/todos", async (TodoDb db) => await db.Todos.ToListAsync())
    .WithName("GetTodos");

Skip this on either package and generators fall back to inventing a method name from the HTTP verb and route — see how to fix missing operationId errors for what that looks like downstream. Name every route you expect customers to call by a stable method name.

From a .NET spec to hosted docs and typed SDKs

Once your spec has explicit operationIds and a version you've confirmed, turning it into an installable SDK is a separate step. With Sourced:

  1. Point Sourced at your repo or the live endpoint. Connect from GitHub, or paste the /swagger/v1/swagger.json or /openapi/v1.json output directly into a new project.
  2. Preview the TypeScript and Python SDKs. Sourced renders both before anything publishes — method names, typed models, error classes — so a verb-and-route fallback method name shows up in the preview, not a customer's autocomplete.
  3. Get hosted docs and an llms.txt from the same spec. No separate docs deploy — the hosted docs preview and llms.txt come from the same pass as the SDKs.
  4. Publish on your schedule. Free unlimited previews and up to 2 hosted noindex docs review sites and one hosted MCP server, no credit card, cover steps 1-3.

Comparison: Swashbuckle vs. Microsoft.AspNetCore.OpenApi vs. a full SDK pipeline

Need Swashbuckle.AspNetCore Microsoft.AspNetCore.OpenApi What neither gives you
A generated OpenAPI spec Yes, /swagger/v1/swagger.json Yes, /openapi/v1.json Nothing — both do this for free
Third-party dependency Yes No (built into ASP.NET Core 9+)
Interactive API browsing Built-in Swagger UI None — needs a separate UI package A hosted docs site for external customers
OpenAPI 3.1 support Yes, since v10.0 Yes, default from .NET 10
A typed client SDK Nothing built in Nothing built in Generated TypeScript or Python SDK
A diff before a breaking release Nothing built in Nothing built in A compatibility report
Agent-readable docs Nothing built in Nothing built in llms.txt derived from the spec

OSS generators for other languages

Sourced's generated SDKs focus on TypeScript and Python today — the two ecosystems where teams publish first, not C#. For the SDK itself, a clean .NET-emitted spec works with the standard per-language OpenAPI Generator ecosystem — C# itself for consumers who want a generated client instead of hand-written, plus Java, Go, Ruby, PHP, Kotlin, Rust, and Swift. Sourced still fits on that same spec for hosted docs, llms.txt, and validation. The five-minute generate-an-SDK guide covers running a local generator against any spec.

Other backend frameworks with their own spec-extraction paths: FastAPI, NestJS, Express, Django, Rails, Spring Boot, and Laravel.

Honest scope: when the built-in tooling is enough

If your .NET API only serves internal or same-team consumers, Microsoft.AspNetCore.OpenApi's zero-dependency spec plus a shared HttpClient wrapper is a reasonable stopping point — you already own both ends. If you need a browsable UI without adding Swashbuckle, tools like Scalar can read the built-in package's output directly. Reach for full SDK generation once you have external customers, a second language to support, or a docs site that needs to outlive whichever package generated the spec.

FAQ

Does .NET generate OpenAPI automatically?

Since .NET 9, yes — Microsoft.AspNetCore.OpenApi is built into ASP.NET Core and generates a spec at /openapi/v1.json with two lines of code (AddOpenApi(), MapOpenApi()). Before .NET 9, or if you want a bundled Swagger UI, Swashbuckle.AspNetCore is the standard third-party option.

What's the difference between Swashbuckle and Microsoft.AspNetCore.OpenApi?

Swashbuckle.AspNetCore is a third-party package with a bundled Swagger UI, supporting ASP.NET Core 8.0+. Microsoft.AspNetCore.OpenApi is Microsoft's own built-in package (.NET 9+) for spec generation only — it has no UI of its own, so you pair it with a separate package like Swagger UI or Scalar if you want interactive browsing.

What OpenAPI version does the built-in package generate by default?

It depends on your .NET version: OpenAPI 3.0 by default on .NET 9, flipping to 3.1 by default starting with .NET 10. Set options.OpenApiVersion explicitly in AddOpenApi() if you need a specific version regardless of framework version.

Why is my generated SDK's method named after the HTTP verb and route instead of something readable?

Because operationId wasn't set. Both Swashbuckle.AspNetCore and Microsoft.AspNetCore.OpenApi omit it by default — Swashbuckle's own docs say so explicitly. Set a Name on controller routes, or call .WithName(...) on minimal API endpoints, to get stable, generator-friendly method names.

Does Swashbuckle.AspNetCore support OpenAPI 3.1?

Yes, as of its 10.x major version, via an upgrade to Microsoft.OpenApi 2.x. Earlier major versions were limited to OpenAPI 3.0 (branded "swagger.json" but structurally OpenAPI 3.0) and Swagger 2.0. Check your installed version before assuming.

Can I use both Swashbuckle and Microsoft.AspNetCore.OpenApi together?

You can, but there's little reason to run both for the same document — they'd produce two separate specs. More common: Microsoft.AspNetCore.OpenApi for generation plus a separate UI package for browsing, without adopting all of Swashbuckle.

Ship it

Once your spec has explicit operationIds and a confirmed OpenAPI version, you have a real .NET OpenAPI SDK source to work with. Start free on Sourced to preview a TypeScript and Python SDK plus hosted docs from that spec in one pass, or run it through the OpenAPI validator first to catch naming and version gaps before you generate anything.