Fullstack API runtime

apiLoaderPlugin prod vs dev paths OpenAPI RFC catalog Link headers cold bundles.

Fullstack API runtime

When config.mode !== 'frontend', createManicServer (packages/manic/src/server/index.ts) mounts the filesystem API tree via apiLoaderPlugin.


Loader roots

const { app: apiApp, openApiSpec } = await apiLoaderPlugin(
  prod ? `${dist}/api` : 'app/api'
);
EnvironmentDirectory scannedNotes
Production<dist>/api prebuilt *.js outputsMatches manic build per-entry bundles (Bundler transform)
Developmentapp/api TypeScript sourcesSame globs as plugin (.ts, .tsx, .js)

Mounted endpoints

RouteResponsibility
/api, /api/*Forward to apiApp.fetch (Hono basePath('/api'))
/openapi.jsonSerialized openApiSpec from loader
/.well-known/api-catalogRFC 9727 linkset pointing at /openapi.json

Built-in Link headers advertise openapi + api-catalog + MCP discovery URI (Server runtime).


Why this stays “fast” at deploy time

  1. Per-route bundles — serverless adapters ship only the JS for each app/api/**/index.ts entry (Performance model).
  2. No monolithic API graph — avoids importing every handler into one cold-start blob unless your code statically pulls them together.
  3. Prod scans compiled JS — loader skips TS compilation overhead at runtime.

Frontend mode contrast

mode: 'frontend' skips apiLoaderPlugin entirely — pure SPA Bun.serve surface (Server runtime).


See also

On this page