For AI agents: the complete documentation index is available at https://dotpress.dev/llms.txt, the full documentation bundle is available at https://dotpress.dev/llms-full.txt, and this page is available as Markdown at https://dotpress.dev/reference/application.md.

Application

createApp() and the object it returns. For an introduction, see How it works.

createApp()

import { createApp } from '@dotpress/core'

function createApp(options: AppOptions): Promise<App>

createApp() sets up the plugins, compiles the routes, runs the onInit hooks, mounts the routes on the adapter, then runs the onReady hooks. It does not start a server: call app.listen(), or hand the app to a serverless handler.

Options

OptionTypeDefaultDescription
adapterHttpAdapterrequiredThe HTTP adapter: Express, Fastify, Hono, AWS Lambda.
routersRouter[][globalRouter]The routers to mount. Without it, the routes declared with defineRoute(). See Routers.
pluginsPlugin[][]Set up in the given order, dependencies first. See Plugin API.
middlewaresMiddleware[][]Run on every route, after the plugin middlewares, before the group and route middlewares.
responseFiltersResponseFilter[][]Applied to every successful JSON result, before the plugin and router filters.
basePathstring—Prefix of every route, plugin routes included, when the proxy forwards the full path.
publicBasePathstring—Prefix removed by the proxy: routes are not prefixed, but publicPath() is. Cannot be combined with basePath.
corsCorsOptionsdisabledAnswers cross-origin requests. See CORS options.
loggerLoggerconsole loggerAny logger with the Logger interface, Pino included.
exposeErrorsbooleanfalseAdds the name, message and stack of unexpected errors to 500 responses. Never in production.
generateRequestId(request: NormalizedRequest) => stringcrypto.randomUUID()The ID of each request, sent as X-Request-ID.
onError(error: unknown, ctx: RequestContext | undefined) => void | Promise<void>—Called with every unexpected error (anything but an HttpError). ctx is undefined outside a route.

The body size limit is an option of the adapter (bodyLimit, 1 MiB by default), or of a route. See Common options.

Startup errors

createApp() rejects, instead of starting with a wrong configuration, when:

  • adapter is missing;
  • basePath and publicBasePath are both set, or one is not a valid path;
  • two routes have the same method and path (Route conflict: "GET /articles/:id" is already defined…);
  • a plugin is installed twice, depends on a plugin that is not installed, or the dependencies are circular;
  • two plugins provide the same context key;
  • the cors option is invalid, for instance origin: '*' with credentials: true;
  • a setup(), onInit or onReady hook throws.

Route definitions are checked when they are declared: a path with unsupported syntax, an unknown method or an invalid status throws at defineRoute().

App

MemberDescription
listen(port, host?)Starts the server. Not available on serverless adapters.
close()Stops the server, waits for the pending requests and closes the streamed responses, then runs the onClose hooks of the plugins, last plugin first. Rejects with the first failing hook, after running them all.
routesThe mounted routes (RouteInfo[]), with the base path: method, path, path parameters, schemas, metadata, security, status.
pluginsThe installed plugins, in setup order.
basePath, publicBasePathThe normalized options, or ''.
publicPath(path)The path seen by the browser: app.publicPath('/login') gives '/my-app/api/login' with a base path.
loggerThe logger of the app.
adapterThe adapter given to createApp().
native()The native application of the adapter: Express app, Fastify instance, Hono app.
const app = await createApp({ adapter: expressAdapter(), routers, plugins })
await app.listen(3000)

process.once('SIGTERM', () => void app.close())

CORS options

cors: {
  origin: ['https://app.example.com', /\.example\.com$/],
  credentials: true,
  exposedHeaders: ['X-Request-ID'],
  maxAge: 600,
}
OptionTypeDefaultDescription
originsee belowrequiredThe allowed origins.
credentialsbooleanfalseAllows cookies and fetch() with credentials: 'include'. Not with origin: '*'.
allowedHeadersstring[]the requested headersRequest headers allowed by preflight responses.
exposedHeadersstring[]noneResponse headers readable by the browser, besides the safelisted ones.
maxAgenumber—How long browsers cache preflight responses, in seconds.

origin accepts '*' (any origin, without credentials), an origin ('https://app.example.com'), a regular expression, a list of origins and regular expressions, or a function (origin, request) => boolean | Promise<boolean>.

See CORS for preflight requests and error responses.

Logger

interface Logger {
  debug: LogFn
  info: LogFn
  warn: LogFn
  error: LogFn
  child(bindings: Record<string, unknown>): Logger
}

interface LogFn {
  (message: string, ...args: unknown[]): void
  (data: object, message?: string, ...args: unknown[]): void
}

The signature is the one of Pino: logger: pino() works as is. The default logger writes to the console:

import { createConsoleLogger } from '@dotpress/core'

const logger = createConsoleLogger({ level: 'debug', bindings: { service: 'api' } })
OptionDefaultDescription
level'info'debug, info, warn or error.
bindings{}Fields added to every entry.

See Logging.

For adapter authors

@dotpress/core also exports what an adapter needs: the HttpAdapter contract, CompiledRoute and DotpressRuntime, createRouteMatcher(), parseQueryString(), parseRequestBody(), DEFAULT_BODY_LIMIT, and for adapters built on the Web Request and Response, fromWebRequest(), readRequestBody() and toWebResponse(). The rules every adapter follows are documented on the HttpAdapter interface, and checked by the conformance suite.