Silgi

OpenAPI

Auto-generated OpenAPI 3.1 spec from your router — per-procedure metadata, path parameters, security, and custom overrides.

Silgi generates a full OpenAPI 3.1.0 specification from your router automatically. Every procedure becomes an operation — input schemas become request bodies or query parameters, output schemas become response bodies, and typed errors become error responses.

Enable

Pass scalar: true to serve() or handler():

s.serve(appRouter, {
  : true,
})

This serves:

  • /openapi.json — the raw OpenAPI specification
  • /reference — interactive API docs powered by Scalar

Procedure metadata

Use $route() to add OpenAPI metadata to any procedure:

const  = s
  .$route({
    : 'GET',
    : '/users/:id',
    : 'Get user by ID',
    : 'Returns a single user by their numeric ID.',
    : ['Users'],
    : 'getUserById',
    : false,
    : 200,
    : 'User found',
  })
  .$input(z.object({ : z.number() }))
  .$output(UserSchema)
  .$errors({ : 404 })
  .$resolve(...)
OptionTypeDefaultDescription
methodstring'POST'HTTP method (GET, POST, PUT, DELETE, etc.)
pathstringauto from routerCustom URL path (supports :param, :param(regex), **)
summarystringShort summary shown in API docs
descriptionstringDetailed description (supports markdown)
tagsstring[]auto from routerTags for grouping operations
operationIdstringauto from routerCustom operation ID for SDK generation
deprecatedbooleanMark as deprecated
successStatusnumber200HTTP status code for success response
successDescriptionstring'Successful response'Description for success response

Path parameters

:param syntax is automatically converted to OpenAPI {param} format with proper parameter declarations:

const  = s
  .$route({ : 'GET', : '/users/:id' })
  .$input(z.object({ : z.number() }))
  .$resolve(...)

// Spec: GET /users/{id}
// parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }]

Supported patterns:

  • :id — required path parameter
  • :id(\\d+) — parameter with regex constraint
  • :id? — optional parameter
  • ** — catch-all wildcard (becomes {path})

Security

Global security

Set a global security scheme in ScalarOptions:

s.serve(appRouter, {
  : {
    : {
      : 'http',
      : 'bearer',
      : 'JWT',
    },
  },
})

All operations will require this scheme by default.

Per-procedure override

Override security on individual procedures:

// Public endpoint — no auth required
const  = s.$route({ : false }).$resolve(() => ({ : 'ok' }))

// Requires specific scheme
const  = s.$route({ : ['bearerAuth'] }).$resolve(() => ({ : true }))
ValueEffect
falsePublic — security: [] in spec
string[]Named security schemes required
not setInherits global security

Error responses

Typed errors

Errors declared with $errors() are automatically documented:

const  = s
  .$errors({
    : 404,
    : { : 403, : 'Not allowed' },
  })
  .$resolve(...)

// Spec generates: 404 and 403 response entries with error schema

The message field appears as default in the generated schema.

Validation errors

Procedures with $input() automatically get a 400 BAD_REQUEST response in the spec with the validation error schema — no configuration needed.

Guard errors

Errors from guards ($use(authGuard)) are merged into the procedure's error responses:

const  = s.guard({
  : { : 401 },
  : () => { ... },
})

const  = s
  .$use()
  .$errors({ : 403 })
  .$resolve(...)

// Spec: 401 from guard + 403 from procedure

Custom OpenAPI override

For anything not covered by the built-in options, use spec to override or extend the generated operation:

Object merge

s.$route({
  : {
    : { : 'https://docs.example.com/users' },
    'x-rate-limit': 100,
    'x-internal': true,
  },
})

Function override

Receives the auto-generated operation, return the final one:

s.$route({
  : () => ({
    ...,
    'x-codegen-request-body-name': 'body',
    : [
      ...(.parameters ?? []),
      { : 'X-Tenant-ID', : 'header', : true, : { : 'string' } },
    ],
  }),
})

The spec override is applied last — after all auto-generation is complete. It's the escape hatch for any OpenAPI feature not directly supported.

Schema conversion

Silgi uses Standard Schema to convert your validator schemas (Zod, Valibot, ArkType) to JSON Schema. This happens via the ~standard.jsonSchema.input() interface — no Zod-specific introspection needed.

This means the generated OpenAPI spec is accurate for any validator that implements Standard Schema v1, not just Zod.

Tags

Tags are auto-generated from the first router segment:

const  = s.router({
  : {          // tag: "users"
    : ...,
    : ...,
  },
  : {         // tag: "orders"
    : ...,
  },
})

Override with $route({ tags: ['Custom', 'Tags'] }).

What's next?

  • Server — Scalar UI configuration and CDN options
  • Procedures$input(), $output(), $errors() API
  • Middleware — guards with typed errors

On this page