<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Documentation on kmcd.dev</title><link>https://kmcd.dev/tags/documentation/</link><description>Recent content in Documentation on kmcd.dev</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>All Rights Reserved</copyright><lastBuildDate>Tue, 23 Jun 2026 10:00:00 +0000</lastBuildDate><atom:link href="https://kmcd.dev/tags/documentation/index.xml" rel="self" type="application/rss+xml"/><item><title>Introducing ProtoDocs</title><link>https://kmcd.dev/posts/introducing-protodocs/</link><pubDate>Tue, 23 Jun 2026 10:00:00 +0000</pubDate><guid>https://kmcd.dev/posts/introducing-protodocs/</guid><description> 
                &lt;p> &lt;img hspace="5" src="https://kmcd.dev/posts/introducing-protodocs/cover.svg" /> &lt;/p>
                
                A protobuf-first documentation browser for APIs that deserve better than ugly generated docs.
                </description><content:encoded><![CDATA[<p><strong>Protocol Buffers are fantastic for defining API contracts.</strong> They give you a massive ecosystem of tooling, backward compatibility guarantees, and rock-solid schemas. But if you have ever tried sharing protobuf docs with an API consumer, you know the generated documentation story usually feels like a complete afterthought.</p>
<p>Most tooling forces you into a frustrating compromise. You either get docs that are technically complete but too ugly to send to others, or you get something pretty that requires a mountain of custom templates, glue code, and endless project-specific maintenance. Or you just share the protobuf files, which is also not amazing.</p>
<p>That frustration is exactly why I originally built <a href="https://github.com/sudorandom/protoc-gen-connect-openapi" rel="external">protoc-gen-connect-openapi</a>. The OpenAPI ecosystem has tools like Redocly and Swagger UI that give you beautiful, browsable websites out of the box. Translating <a href="https://connectrpc.com" rel="external">Connect APIs</a> into OpenAPI made sense at the time, but it solved the problem in a round-about way. I will say that it works remarkably well, but I wanted a tool that starts from protobuf, keeps the schema front and center, and still looks polished enough to publish.</p>
<p>So I made <strong><a href="https://protodocs.dev/" rel="external">ProtoDocs</a></strong>.</p>
<figure><a href="https://kmcd.dev/posts/introducing-protodocs/eliza-sshot.png" class="spotlight" data-download="true" aria-label="A screenshot of the ProtoDocs interface showing protobuf files, services, messages, and RPC calls.">
    
    
    
    
        
            
            
                
            
            
        
    

    
    
    

    
    
        
    

    <img src="https://kmcd.dev/posts/introducing-protodocs/eliza-sshot_hu_e3e07748f039b0cb.png"
         alt="A screenshot of the ProtoDocs interface showing protobuf files, services, messages, and RPC calls."/>
    </a><figcaption>
            <p>A screenshot of the ProtoDocs interface showing protobuf files, services, messages, and RPC calls.</p>
        </figcaption>
</figure>

<h2 id="protobuf-first-documentation">Protobuf-first documentation</h2>
<p>ProtoDocs is a web-based documentation browser for Protocol Buffer definitions. It is built around protobuf concepts directly: files, packages, services, RPCs, messages, enums, fields, oneofs, options, and comments.</p>
<p>What does &ldquo;protobuf-first&rdquo; actually mean? It means the tool is not ashamed of the raw protobuf source. Personally, I think protobuf schemas are pretty clean, expressive, and highly readable, which is something I definitely can&rsquo;t say for the verbose, nested JSON/YAML of OpenAPI. Instead of hiding the schemas behind abstract templates, ProtoDocs leans into the source code itself. It renders the actual protobuf syntax directly (complete with syntax highlighting), but overlays it with rich, interactive tooltips on everything, from keywords and field names to type references and custom options, making it easy to navigate and learn as you browse.</p>
<p>Fun fact: the configuration of ProtoDocs itself is defined as a Protocol Buffer schema. That means ProtoDocs is self-documenting. You can browse the official configuration options directly on <a href="https://protodocs.dev/#/files/protodocs/v1/config.proto" rel="external">protodocs.dev</a>, which is a pretty fun way to showcase the tool.</p>
<p>The main goal is simple: make protobuf documentation pretty, navigable, and useful without turning it into a completely different API description format first.</p>
<h2 id="what-it-does">What it does</h2>
<p>ProtoDocs gives you a documentation UI that lets you explore the API from a few different angles:</p>
<ul>
<li><strong>Browse files and packages</strong> through a clean directory hierarchy that merges common path prefixes, making large proto trees easier to scan.</li>
<li><strong>Inspect services and RPC methods</strong>, including unary and streaming signatures, alongside custom method options.</li>
<li><strong>Drill into messages</strong>, enums, custom options, oneof declarations, nested types, comments, and linked type references.</li>
<li><strong>Jump to definitions</strong> and find references across the loaded files. Type tooltips can be pinned, allowing you to move from a field to the type declaration or see where a type is used without losing your place.</li>
<li><strong>Interactive &ldquo;Try it out&rdquo; panel</strong> for sending live Connect, <a href="https://github.com/grpc/grpc-web" rel="external">gRPC-Web</a>, and proxied <a href="https://grpc.io" rel="external">gRPC</a> requests (including streaming calls) directly to target RPC services from the browser.</li>
<li><strong>Websocket-based proxy</strong> to tunnel browser requests and streaming calls, avoiding CORS restrictions and enabling direct connection to your services.</li>
<li><strong>Syntax highlighting and interactive help</strong> for the underlying protobuf source code, rendering it cleanly and adding keyword tooltips that explain what they do.</li>
<li><strong>Multiple schema loading options</strong> including serving pre-built descriptor set files (e.g. from <code>buf</code> or <code>protoc</code>), querying live servers using reflection, or reading directly from an in-memory Go registry for embedded usage.</li>
</ul>
<p>As you edit input parameters in the client panel, ProtoDocs also generates command snippets for Connect, <code>grpcurl</code>, and <code>buf curl</code>, serving as a bridge from browser exploration to reproducible terminal commands.</p>
<h2 id="built-for-connect-but-not-only-connect">Built for Connect, but not only Connect</h2>
<p>ProtoDocs is heavily designed around ConnectRPC servers.</p>
<p>That is where the experience feels the most natural to me, because a Connect server can expose the Connect protocol, gRPC, and gRPC-Web from the exact same API surface. ProtoDocs leverages that to provide browser-native exploration while staying close to the real RPC contract.</p>
<p>The interactive client supports:</p>
<ul>
<li>Connect</li>
<li>gRPC-Web</li>
<li>gRPC through proxy mode</li>
</ul>
<p>The documentation side is protobuf-first, so the schema browsing makes sense anywhere you have protobuf descriptors. The richer interactive path is where ConnectRPC servers truly shine.</p>
<figure><a href="https://kmcd.dev/posts/introducing-protodocs/eliza-tryitout-sshot.png" class="spotlight" data-download="true" aria-label="A screenshot showing that you can make requests, similar to swagger.">
    
    
    
    
        
            
            
                
            
            
        
    

    
    
    

    
    
        
    

    <img src="https://kmcd.dev/posts/introducing-protodocs/eliza-tryitout-sshot_hu_4682a155a0087a77.png"
         alt="A screenshot showing that you can make requests, similar to swagger."/>
    </a><figcaption>
            <p>A screenshot showing that you can make requests, similar to swagger.</p>
        </figcaption>
</figure>

<h2 id="three-ways-to-run-it">Three ways to run it</h2>
<p>There are three primary ways to deploy ProtoDocs:</p>
<ul>
<li>Static Website</li>
<li>With a backend</li>
<li>Embedded into Go applications</li>
</ul>
<p>All three of these approaches have strengths and weaknesses, so let&rsquo;s dig into how this works:</p>
<h3 id="static-website">Static website</h3>
<p>ProtoDocs can be hosted as a static site. Put the built frontend on Nginx, S3, Netlify, GitHub Pages, or any other static host, point it at one or more descriptor files, and you have browsable protobuf documentation.</p>
<p>This mode is the simplest deployment. The browser talks directly to your target API server for interactive requests, so your API server needs CORS configured if you want the &ldquo;Try it out!&rdquo; panel to work.</p>
<div class="d2-diagram-wrapper">
    <div class="d2-diagram"
        style="display: block; width: 100%; max-width: 100%; margin-left: auto; margin-right: auto; max-height:70vh; width:100%;"><img src="/d2-diagrams/aa9d335ef5502f1a4d9ac6c99a7cb0d76e3e2191d112456ac551678f1a47731e.svg" alt="D2 Diagram" loading="lazy" style="max-width: 100%; max-height: inherit; width: 100%; height: auto; object-fit: contain; display: block; margin: 0 auto;" /></div>
</div>
<h3 id="website-with-a-small-backend">Website with a small backend</h3>
<p>ProtoDocs can also run with a small backend proxy.</p>
<p>In this mode, browser requests and streaming calls tunnel through the proxy. That avoids CORS problems and lets the backend forward requests to gRPC, gRPC-Web, or Connect services.</p>
<div class="d2-diagram-wrapper">
    <div class="d2-diagram"
        style="display: block; width: 100%; max-width: 100%; margin-left: auto; margin-right: auto; max-height:70vh; width:100%;"><img src="/d2-diagrams/529635df2c14bfe1e1c07278a29ede62129e7e906b9a83a9f476d228e6ecc92f.svg" alt="D2 Diagram" loading="lazy" style="max-width: 100%; max-height: inherit; width: 100%; height: auto; object-fit: contain; display: block; margin: 0 auto;" /></div>
</div>
<p>I expect this mode to be the most useful for internal tools and developer portals where &ldquo;open the docs and call the API&rdquo; needs to work out of the box.</p>
<h3 id="embedded-go-handler">Embedded Go handler</h3>
<p>ProtoDocs can be embedded directly into a Go HTTP server.</p>
<p>This gives you the documentation UI, descriptor loading from the Go registry, and the proxy path all from the same application. If you already have a Go service exposing Connect or gRPC handlers, mounting ProtoDocs alongside it makes the service self-documenting without requiring a separate docs deployment.</p>
<p>At a high level, it looks like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;"><code class="language-go" data-lang="go"><span style="display:flex;"><span>handler<span style="color:#eceff4">,</span> err <span style="color:#81a1c1">:=</span> protodocs<span style="color:#eceff4">.</span><span style="color:#88c0d0">NewHandler</span><span style="color:#eceff4">(</span>protodocs<span style="color:#eceff4">.</span>Config<span style="color:#eceff4">{</span>
</span></span><span style="display:flex;"><span>    Title<span style="color:#eceff4">:</span>    <span style="color:#a3be8c">&#34;My Service Documentation&#34;</span><span style="color:#eceff4">,</span>
</span></span><span style="display:flex;"><span>    LogoText<span style="color:#eceff4">:</span> <span style="color:#a3be8c">&#34;My Service&#34;</span><span style="color:#eceff4">,</span>
</span></span><span style="display:flex;"><span>    Registry<span style="color:#eceff4">:</span> protoregistry<span style="color:#eceff4">.</span>GlobalFiles<span style="color:#eceff4">,</span>
</span></span><span style="display:flex;"><span>    Prefix<span style="color:#eceff4">:</span>   <span style="color:#a3be8c">&#34;/docs/&#34;</span><span style="color:#eceff4">,</span>
</span></span><span style="display:flex;"><span><span style="color:#eceff4">})</span>
</span></span><span style="display:flex;"><span><span style="color:#81a1c1;font-weight:bold">if</span> err <span style="color:#81a1c1">!=</span> <span style="color:#81a1c1;font-weight:bold">nil</span> <span style="color:#eceff4">{</span>
</span></span><span style="display:flex;"><span>    log<span style="color:#eceff4">.</span><span style="color:#88c0d0">Fatal</span><span style="color:#eceff4">(</span>err<span style="color:#eceff4">)</span>
</span></span><span style="display:flex;"><span><span style="color:#eceff4">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>http<span style="color:#eceff4">.</span><span style="color:#88c0d0">Handle</span><span style="color:#eceff4">(</span><span style="color:#a3be8c">&#34;/docs/&#34;</span><span style="color:#eceff4">,</span> handler<span style="color:#eceff4">)</span>
</span></span></code></pre></div><h2 id="themes-source-and-sharp-edges">Themes, source, and sharp edges</h2>
<p>ProtoDocs has light, dark, and cyberpunk themes. They can follow system preferences or be toggled manually.</p>
<p>It can render source views, markdown comments, structured options, package trees, service lists, search results, and linked type details. The idea is to make the source schema readable without forcing people to clone a repo, find the right proto directory, and mentally resolve every import by hand.</p>
<p>It is also still early days.</p>
<p>There are bugs. There are parts of the UI and runtime behavior that will inevitably change as the project gets more real-world use.</p>
<p>But it is far enough along that I want people to try it, complain about what is confusing, and show me the protobuf schemas that break it. If you run into any sharp edges, have feedback on how to improve the layout, or want to contribute a fix, please head over to GitHub to open an issue or submit a PR!</p>
<h2 id="try-it">Try it</h2>
<p>You can try the live demo at <strong><a href="https://protodocs.dev/" rel="external">protodocs.dev</a></strong>.</p>
<a href="https://github.com/sudorandom/protodocs" target="_blank" rel="noopener noreferrer" class="github-repo-card">
  <div class="github-repo-card-header">
    <div class="github-repo-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg></div>
    <span class="github-repo-name">sudorandom/protodocs</span>
  </div><p class="github-repo-description">A protobuf-first documentation browser for APIs that deserve better than ugly generated docs.</p></a>

<p>If you have a ConnectRPC, gRPC-Web, or descriptor-heavy protobuf project, I would love for you to point ProtoDocs at it and see where it falls over.</p>
]]></content:encoded></item></channel></rss>