Scalar API Reference UI¶
Baldr ships an interactive Scalar UI inside the library — no CDN, no runtime files. The bundle is pulled into the translation unit via std::embed (C++26, P1967R14) and served from process memory by a one-liner helper.
Baldr's Scalar bundle
Version 1.62.4 is vendored under src/Baldr/OpenApi/Assets/ (JS bundle, stylesheet, HTML wrapper, MIT notice). The library is compiled directly with #embed, so the bytes live in the same .text section as your code and use the same linker treatment.
Quick start¶
Add the helper after your routes are registered, then run:
#include <Baldr/Baldr.hpp>
int main()
{
auto builder =
skr::ApplicationBuilder()
.WithExtension<baldr::BaldrExtension>()
.WithExtension<baldr::BaldrOpenApiExtension>([](auto& ext) {
baldr::OpenApiOptions opts;
opts.info.title = "Devices API";
opts.info.version = "1.0.0";
ext.WithOptions(opts);
});
auto app = builder.Build<baldr::WebApplication>();
app->MapGet("/api/devices").Handle([] { /* ... */ });
baldr::MapScalarUi(*app);
app->Run();
}
As soon as MapScalarUi is called — before any request reaches the UI — Baldr logs a line you can ctrl+click in any modern terminal:
[Information] 2026-... 'baldr::ScalarUi': Scalar UI listening at http://0.0.0.0:8080/scalar (spec: /openapi.json)

The URL picks up the actual HttpServerOptions::port, so the line keeps working even when you change the bind port. If you skip BaldrExtension and wire the application manually, the helper logs a warning with the mount path instead — still clickable as a relative URL.
What gets mounted¶
| Route | Source | Content-Type |
|---|---|---|
mountPath (default /scalar) |
HTML wrapper with the placeholders __TITLE__, __SPEC_URL__, __JS_URL__, __STYLES_URL__, and __CONFIGURATION__ rewritten against mountPath, specUrl, and pageTitle (see MapScalarUi.cpp:71-77) |
text/html; charset=utf-8 |
mountPath/scalar-reference.js |
Scalar's UMD bundle (~3.7 MB) | application/javascript; charset=utf-8 |
mountPath/styles.css |
Scalar stylesheet (~289 KB) | text/css; charset=utf-8 |
The HTML wrapper contains a <script id="api-reference" data-spec-url="..."> element followed by the Scalar UMD loader. Scalar fetches the spec URL client-side, so the API itself can remain private to your network.
Customisation¶
MapScalarUi has four parameters:
baldr::MapScalarUi(WebApplication& app,
std::string mountPath = "/scalar",
std::string specUrl = "/openapi.json",
std::string pageTitle = "API Reference");
| Parameter | Default | Notes |
|---|---|---|
mountPath |
/scalar |
Force-prefixed with / if missing. Trailing-mount pairs (e.g. /docs/api) are accepted. |
specUrl |
/openapi.json |
Path (or URL) the Scalar client fetches. Override when your spec lives behind an authenticated gateway or a different prefix. |
pageTitle |
API Reference |
Goes into the <title> element and into your browser tab. |
To switch to a darker brand colour, supply a custom HTML wrapper rather than the built-in one: copy src/Baldr/OpenApi/Assets/index.html, tweak the <title> and the <script data-configuration> attribute, and serve it from your own static-files route. The Scalar client loads the rest from /scalar/scalar-reference.js and /scalar/styles.css.
Architecture¶
MapScalarUi lives in src/Baldr/OpenApi/MapScalarUi.{hpp,cpp}. The bytes are pulled in at compile time from the same translation unit that mounts the routes:
const unsigned char kScalarReferenceJs[] = {
#embed "Assets/scalar-reference.js"
};
#embeddrops the file's bytes inline as a namespace-scope array. gcc-15+ is the minimum compiler that implements the feature (CI pinsgcc-16), so no CMake generator, noxxd, noobjcopy— just normal C++ you can read in the editor.- Each asset has a matching
kScalar*Sizeconstant (justsizeof(...)), made available alongside for completeness. OpenApi::EmbeddedScalar::AsStringViewwraps each byte array in a non-owningstd::string_viewbecauseContentResulttakes astd::string body. The view's source is the#embedarray, which has program lifetime.
When not to use it¶
- You already serve a UI from another process.
MapScalarUicollides only on the prefix you pass asmountPath; pick something else or skip the helper. - You want a different UI (Swagger UI, Redoc, Stoplight Elements). Use the same pattern with your own asset bundle — the helper is intentionally a single function so it's easy to fork, and the build system does not require any change.
Limitations¶
- The Scalar bundle is 3.7 MB; it adds that much to your binary's size. Strip it with
strip -s/-R .comment --strip-unneededpost-build if you care. - The library does not deduplicate the bundle between translation units. The compiler's linker can drop it if no TU references
MapScalarUi, but every call embeds it once at most. - The HTML wrapper is a static template. If you want to inject a navigation bar, switch themes, or pass extra
<meta>tags, copy the template into your own example and pass an override — see Customisation. - Scalar's standalone bundle evaluates its data-spec URL on the client. If
/openapi.jsonrequires anAuthorizationheader, configure your CORS / auth middleware to allow the browser request through.
Next steps¶
- Browse the
OpenApiExampleprogram for end-to-end usage. - Read OpenAPI extension for spec options and the JSON Schema dialect.
- See
MapScalarUi.hppfor the implementation.