Telaio
API Reference

Builder API Reference

Complete reference for createApp(), AppBuilder, and TelaioApp.

Builder API Reference

createApp()

function createApp<TConfig extends Record<string, unknown> = Record<string, never>>(
  options?: CreateAppOptions<TConfig>,
): AppBuilder<DefaultFeatures, unknown, TConfig>

Entry point for every Telaio application. Returns an AppBuilder with all feature flags set to false (DefaultFeatures). Nothing is constructed until you call .build().

CreateAppOptions

interface CreateAppOptions<TConfig extends Record<string, unknown> = Record<string, never>> {
  config?: TConfig;
  logger?: Logger;
}
OptionTypeDescription
configTConfigValidated config object from loadConfig(). Passed through to TelaioApp.config.
loggerLoggerPino logger instance. If omitted, a default logger is created.

AppBuilder<F, TSession, TConfig>

The builder accumulates configuration across method calls. Each method returns a new AppBuilder with updated type parameters. The three type parameters are inferred -- you never write them explicitly.

ParameterPurposeDefault
F extends FeaturesWhich optional features are activeDefaultFeatures
TSessionShape of the authenticated session objectunknown
TConfigType of the config objectRecord<string, never>

Methods

.withDatabase(options?)

withDatabase(options?: WithDatabaseOptions): AppBuilder<F & { database: true }, TSession, TConfig>

Registers a pg pool and Kysely instance. Sets the database feature flag to true, which makes pool and db available on the built TelaioApp.

If options.pool and options.db are provided, those pre-built instances are reused instead of creating new ones. This is used for the auth chicken-and-egg pattern.

.withCache(options?)

withCache(options?: WithCacheOptions): AppBuilder<F & { cache: true }, TSession, TConfig>

Registers a Redis-backed cache. Sets the cache feature flag to true, making cache available on the built TelaioApp. If options.enabled is false (or REDIS_ENABLED=false in config), a no-op stub is used and no Redis connection is opened.

.withQueues(registry, options?)

withQueues<TQueues extends QueueRegistry>(
  registry: TQueues,
  options?: WithQueueOptions,
): AppBuilder<F & { queue: true }, TSession, TConfig>

Registers a pg-boss producer and typed job consumers. The registry argument maps queue names to handler functions. Sets the queue feature flag to true, making queue (a typed QueueProducer<TQueues>) available on the built TelaioApp.

const registry = {
  'send-email': async (jobs) => { /* ... */ },
  'process-upload': async (jobs) => { /* ... */ },
} satisfies QueueRegistry;

createApp({ config }).withQueues(registry);

.withAuth(adapter)

withAuth<S>(adapter: AuthAdapter<S>): AppBuilder<F & { auth: true }, S, TConfig>

Registers the auth Fastify plugin. Sets the auth feature flag to true and narrows TSession to S, which is the session type returned by adapter.getSession(). Makes auth available on the built TelaioApp.

.withSwagger(options)

withSwagger(options: SwaggerOptions): AppBuilder<F, TSession, TConfig>

Registers Fastify's @fastify/swagger plugin with the given options. Does not change type parameters. Must be called before routes are registered -- Telaio enforces this ordering automatically during .build().

.withApiDocs(options?)

withApiDocs(options?: ScalarOptions): AppBuilder<F & { apiDocs: true }, TSession, TConfig>

Registers the Scalar API reference UI at /docs (JSON spec at /docs/json). Sets the apiDocs feature flag to true. Requires .withSwagger() to have been called first.

.withPlugins(options)

withPlugins(options: PluginOptions): AppBuilder<F, TSession, TConfig>

Configures route autoloading, rate limiting, CORS, and other Fastify plugins. Pass { autoload: false } in tests to disable route autoloading and register routes manually.

.withSchemas(schemasDir)

withSchemas(schemasDir: string | false): AppBuilder<F, TSession, TConfig>

Sets the directory from which TypeBox schemas are auto-registered. Pass false to disable schema autoloading entirely (useful in tests).

.onReady(fn)

onReady(fn: () => Promise<void>): AppBuilder<F, TSession, TConfig>

Registers a hook that is called after fastify.listen() completes. Skipped when .asEphemeral() is used.

.onClose(fn)

onClose(fn: () => Promise<void>): AppBuilder<F, TSession, TConfig>

Registers a hook that is called during graceful shutdown (before fastify.close()). Skipped when .asEphemeral() is used.

.withTempFiles()

withTempFiles(): AppBuilder<F, TSession, TConfig>

Enables temporary file upload support via @fastify/multipart. Required if any route handler accesses request.tempFiles.

.asEphemeral()

asEphemeral(): AppBuilder<F, TSession, TConfig>

Marks the builder as ephemeral. In ephemeral mode, lifecycle hooks registered with .onReady() and .onClose() are skipped. Intended for test apps and short-lived CLI invocations.

.build()

async build(): Promise<TelaioApp<F, TSession, TConfig>>

Assembles the application. Performs a fixed 12-step assembly (see Build assembly order). Returns a TelaioApp typed according to the accumulated feature flags.


WithDatabaseOptions

interface WithDatabaseOptions {
  pool?: pg.Pool;
  db?: Kysely<unknown>;
  poolOptions?: PoolOptions;
  databaseOptions?: DatabaseOptions;
  citext?: boolean;
}
OptionTypeDefaultDescription
poolpg.PoolPre-built pool to reuse (skips internal pool creation)
dbKysely<unknown>Pre-built Kysely instance to reuse (skips internal db creation)
poolOptionsPoolOptionsPool options used when creating a pool internally (overrides config)
databaseOptionsDatabaseOptionsKysely options used when creating a db internally (e.g. extra plugins)
citextbooleantrueWhether to register the CITEXT array parser on startup. Set to false if your schema does not use CITEXT[].

WithCacheOptions

interface WithCacheOptions {
  instance?: Cache;
  cacheOptions?: CacheOptions;
}

interface CacheOptions {
  enabled?: boolean;
  url?: string;
}
OptionTypeDefaultDescription
instanceCachePre-built Cache instance to reuse (skips internal creation)
cacheOptionsCacheOptionsCache options when creating internally: enabled (default true) and url (Redis URI)

Note: enabled and url are properties of cacheOptions, not of WithCacheOptions directly.

// Correct:
.withCache({ cacheOptions: { enabled: false } })  // disabled stub

// Incorrect (these fields are ignored):
.withCache({ enabled: false })  // has no effect

WithQueueOptions

interface WithQueueOptions {
  connection?: QueueClientOptions;
}
OptionTypeDescription
connectionQueueClientOptionspg-boss connection options. Falls back to config DATABASE_URL.

TelaioApp<F, TSession, TConfig>

The result of calling .build(). Properties that depend on feature flags are only present when the corresponding flag is true in F.

Always present

PropertyTypeDescription
fastifyFastifyInstanceThe underlying Fastify server instance
configTConfigThe validated config object passed to createApp()
loggerLoggerPino logger instance
start(options?)(options?: StartOptions) => Promise<void>Bind to a port and start accepting requests
stop()() => Promise<void>Gracefully shut down the server and close connections

Conditional (feature-gated)

PropertyRequired featureTypeDescription
pooldatabase: truepg.PoolThe underlying node-postgres pool
dbdatabase: trueKysely<unknown>Kysely query builder instance
cachecache: trueCacheRedis wrapper (or no-op stub if disabled)
queuequeue: trueQueueProducer<TQueues>Typed pg-boss producer
authauth: true{ session: TSession }Phantom type marker only -- not a runtime object. This property does not exist at runtime. Its purpose is to expose TSession through the type system. Access the session at runtime via req.getAuthSession() or req.maybeAuthSession in route handlers.

Accessing a conditional property without enabling the feature is a compile-time error. See Phantom Types.

app.auth is a compile-time phantom type only. It does not exist at runtime -- accessing app.auth will return undefined. The session is available inside route handlers via req.getAuthSession() (throws if not authenticated) or req.maybeAuthSession (null if not authenticated).


StartOptions

interface StartOptions {
  port?: number;
  host?: string;
}
OptionTypeDescription
portnumberPort to listen on. Falls back to API_LISTEN_PORT from config, then 4001.
hoststringHost address to bind. Falls back to API_LISTEN_ADDRESS from config, then '0.0.0.0'.

Features

interface Features {
  database: boolean;
  cache: boolean;
  queue: boolean;
  auth: boolean;
  apiDocs: boolean;
}

The complete set of feature flags. The TelaioApp conditional type reads each flag to determine which properties to expose.


DefaultFeatures

type DefaultFeatures = {
  database: false;
  cache: false;
  queue: false;
  auth: false;
  apiDocs: false;
};

The initial feature set returned by createApp(). All flags are false. Each with*() call merges { featureName: true } into F.

On this page