API Docs

Scalar UI

Serve an interactive API reference next to your spec, and style it.

openapi.SetupDocsEndpoints serves a Scalar reference page that reads your generated spec. Readers get a searchable endpoint list, request and response schemas, and a client for trying calls.

Serve it

openapi.SetupDocsEndpoints(app)
PathContents
/docsThe Scalar reference page
/openapi.jsonThe generated document
/docs/A permanent redirect to /docs

All three are registered Public(), so they work without a token even when the rest of the app requires one.

Configure it

openapi.SetupDocsEndpoints(app, openapi.ScalarConfig{
    Title:       "Orders API",
    Theme:       "deepSpace",
    Layout:      "modern",
    DarkMode:    true,
    ShowSidebar: true,
    HideModels:  false,
    FavIcon:     "/favicon.ico",
})
FieldValuesDefault
TitleAny string, used as the page titleAPI Documentation
Themedefault, alternate, moon, purple, solarized, bluePlanet, saturn, kepler, mars, deepSpacedefault
Layoutmodern, classicmodern
DarkModeboolfalse
ShowSidebarbooltrue in the default config
HideModelsbool, hides the schema listfalse
CustomCSSCSS injected into the pageempty
FavIconURL of a faviconempty

openapi.DefaultScalarConfig() returns the defaults if you want to start from them and change one field.

Use custom paths

openapi.ServeScalar(app, "/openapi.json", "/reference", openapi.ScalarConfig{
    Title: "Orders API",
})

The first path serves the spec, the second serves the UI. The UI fetches the spec path from the browser, so it has to be reachable by whoever opens the page.

Restrict who can read the docs

Public docs are convenient internally and often unwanted in production. Two straightforward options.

Serve them only outside production:

if os.Getenv("APP_ENV") != "production" {
    openapi.SetupDocsEndpoints(app, cfg)
}

Or gate them with middleware on a group, keeping the paths but requiring a credential:

docs := app.Group("/internal").Use(basicAuth(os.Getenv("DOCS_USER"), os.Getenv("DOCS_PASS")))
docs.GET("/openapi.json", specHandler).Public()
docs.GET("/docs", uiHandler).Public()

Because ServeScalar registers on the app rather than a group, this variant means writing the two small handlers yourself, as shown in OpenAPI.

Style it

CustomCSS is injected into a <style> tag, which is enough to match a brand:

openapi.SetupDocsEndpoints(app, openapi.ScalarConfig{
    Title:    "Orders API",
    DarkMode: true,
    CustomCSS: `
        :root {
            --scalar-color-accent: #00add8;
            --scalar-font: "Inter", system-ui, sans-serif;
        }
    `,
})

Helper functions exist for building a config in steps:

cfg := openapi.DefaultScalarConfig()
openapi.ApplyScalarOptions(&cfg,
    openapi.WithCustomTheme("moon"),
    openapi.WithDarkMode(true),
    openapi.WithLayout("classic"),
)
openapi.SetupDocsEndpoints(app, cfg)

Know the constraints

The page loads the Scalar bundle from cdn.jsdelivr.net. A machine with no internet access, or a strict Content-Security-Policy, will render an empty page. If either applies, serve the spec with ezz and host the viewer yourself, or vendor the bundle and serve it from your own static assets.

The spec is built once, on the first request to the spec path, and served from cache after that. Responses carry an ETag, so a client sending If-None-Match gets a 304 Not Modified instead of the full document.

Because the document is cached, routes registered after that first request will not appear in it. Register every route before the server starts serving, which is what route setup normally does anyway.

Generator.SpecJSON is the entry point the endpoint uses: it builds the document once, caches the bytes, and is safe to call from any number of goroutines. Generator.GenerateFromApp returns the *Spec itself, for a build step that writes a spec file or a test that asserts on the document. It rebuilds on every call, but the spec it hands back owns its components, so you can hold it, marshal it, or edit it without the generator changing underneath you.

Next steps

  • OpenAPI for what goes into the document.
  • Testing for asserting the spec in CI.
Copyright © 2026