Skip to main content

Command Palette

Search for a command to run...

Where does /openapi/v1.json actually come from?

Updated
3 min read
A

👋 Hey, I'm Ankit Bajpai!

Software engineer building scalable systems and exploring the intersection of clean code, architecture, and AI.

🎯 What I Write About

I document my learning journey through practical, code-heavy articles on:

  • .NET & ASP.NET Core - Modern web development with C#
  • System Design - LLD patterns, HLD architectures, and scalability
  • Clean Code & Architecture - SOLID, design patterns, and maintainable systems
  • Gen AI for Developers - LLMs, RAG, and AI-powered development

💡 My Approach

Learn → Build → Document → Share

I learn from books, courses, and real projects, then break down complex concepts into digestible tutorials with working code examples. Think of this as my public learning journal that helps you skip the confusion I faced.

🚀 Currently Exploring

  • Clean Architecture in .NET
  • LLM integration with Semantic Kernel
  • System design interview patterns
  • Microservices and event-driven architecture

📬 Let's Connect

Subscribe for weekly deep dives into .NET, system design, and modern software engineering. No fluff—just practical knowledge you can apply immediately.

Happy coding! 🎉

Introduction

If you’ve worked with ASP.NET Core APIs, you’ve definitely hit /openapi/v1.json (or /swagger/v1/swagger.json) at least once.

For a long time, I assumed this file was:

  • generated at startup, or

  • stored somewhere on disk, or

  • magically handled by Swagger UI

Turns out—none of that is true.

Here’s what actually happens under the hood.


🚫 First, a myth to bust

/openapi/v1.json does not live on disk.

There is no physical JSON file sitting inside your project or deployment.

Instead, it’s:

  • generated on-demand

  • cached in memory

  • served only when requested

This design is very intentional.


🔧 What sets everything up?

1️⃣ AddOpenApi()

This registers the OpenAPI document generation services into Dependency Injection.

Think of it as:

“Hey ASP.NET Core, be ready to generate an OpenAPI spec if someone asks.”

No JSON is generated yet.


2️⃣ AddControllers()

This is where most of the heavy lifting actually happens.

At startup, ASP.NET Core:

  • scans all controllers

  • reads routes, attributes, HTTP verbs

  • understands request/response types

  • caches this metadata internally

This metadata is reused for routing, model binding, validation — and later for OpenAPI.


🌐 How does /openapi/v1.json appear?

3️⃣ MapOpenApi()

This registers a single endpoint:

/openapi/v1.json

Important things to note:

  • It’s not part of the request pipeline

  • It doesn’t intercept API calls

  • It only responds when this exact route is hit


⚡ What happens on the first request?

When someone hits /openapi/v1.json for the first time:

  1. OpenAPI services read the cached controller metadata

  2. The OpenAPI JSON spec is built on-demand

  3. The generated document is cached in memory

No disk IO. No regeneration on every request.


🚀 What about subsequent requests?

After the first request:

  • The already-generated document is served from memory

  • Responses are fast

  • No recomputation happens

So the cost is paid once—only if someone actually asks for it.


🧠 Why not generate it at startup?

Because:

  • Startup time matters

  • Many services never expose Swagger/OpenAPI publicly

  • Generating a document no one requests is wasted work

On-demand + caching is a smart tradeoff.


🛑 Why is it usually inside IsDevelopment()?

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

This is not a performance concern.
It’s a security concern.

Leaving it enabled in production:

  • exposes your entire API surface

  • leaks models, routes, and structure

  • helps attackers understand your system faster


⚠️ Rare edge cases

You might notice a small delay on the first request if:

  • you have hundreds of controllers

  • very deep or complex models

  • heavy use of generics and polymorphism

Even then, we’re talking milliseconds, and only once.


✅ Key takeaways

  • /openapi/v1.json is not a file

  • It’s generated on first request

  • It uses already-cached controller metadata

  • The result is cached in memory

  • It has zero impact on normal API requests

  • Disable it in production for security, not performance

Once you know this, Swagger feels a lot less “magical” and a lot more elegant.

.NET Development

Part 3 of 3

A comprehensive .NET series covering fundamentals to advanced concepts. Learn ASP.NET Core, Clean Architecture, Dependency Injection, and modern .NET practices with practical examples—ideal for developers exploring the .NET ecosystem.

Start from the beginning

ASP.NET Core Server-Side Rendering: Choosing Between MVC and Razor Pages

Introduction When building web applications with ASP.NET Core, one of the fundamental decisions you'll face is choosing the right rendering pattern. In this article, I'll break down server-side rendering in ASP.NET Core and help you decide between MV...