No description
  • TypeScript 92.9%
  • JavaScript 7.1%
Find a file
2026-05-19 22:09:12 +02:00
scripts Updated from @temir.ra/template@0.1.3 template. 2026-04-13 17:13:01 +02:00
src Updated from @temir.ra/template@0.1.3 template. 2026-04-13 17:13:01 +02:00
template version 0.4.4 2026-05-19 22:08:47 +02:00
tests version 0.4.4 2026-05-19 22:08:47 +02:00
.gitignore version 0.4.4 2026-05-19 22:08:47 +02:00
CHANGELOG.md version 0.4.4 2026-05-19 22:08:47 +02:00
LICENSE updated generated package for use as a package template 2026-03-06 14:22:38 +01:00
package.json version 0.4.4 2026-05-19 22:08:47 +02:00
README.md version 0.4.4 2026-05-19 22:08:47 +02:00
tsconfig.json version 0.4.4 2026-05-19 22:08:47 +02:00

Introduction

A template for a HTTP server built with Hono and Bun. Provides an opinionated HTTP middleware pipeline, structured request logging, OpenAPI documentation with Scalar UI, and a Bun server host with graceful shutdown. Designed to be used standalone or as the backend in a monorepo alongside one or more @temir.ra/create-hono-spa SPA packages mounted as route groups.

Table of Contents

  1. Quick Start
  2. Documentation
    1. template/
    2. Architecture
    3. src/env.ts
    4. src/app-host.ts
      1. AppEnv
    5. src/server-host.ts
    6. src/middleware/logging/
  3. DevOps
    1. Change Management
    2. Publish

Quick Start

# placeholder:
    # <TEMPLATE_PACKAGE: @temir.ra/create-hono-server
    # <TEMPLATE_NAME: @temir.ra/hono-server
    # <NEW_PACKAGE: <NEW_PACKAGE>
      # is used as:
      #   - the path where the package is created
      #   - the "name" field in the generated package.json
    # <@_VERSION: <@_VERSION>

# pinned version
bun info "@temir.ra/create-hono-server" version
bun create --no-install --no-git "@temir.ra/hono-server<@_VERSION>" <NEW_PACKAGE>

# latest
# clear the cache to pick up the latest version
bun pm cache rm
bun create --no-install --no-git "@temir.ra/hono-server" <NEW_PACKAGE>

# templates only copy files, run install and any setup scripts manually
cd <NEW_PACKAGE>
bun install

Documentation

The following sections explain the configurations and conventions baked into the generated package. Useful when adapting it to fit specific needs.

template/

Official documentation provided by the Hono team is a great resource.

Architecture

The generated server is organized around three roles:

main.ts  →  createAppHost()  →  startServerHost()

main.ts is the entry point and orchestrator. It calls createAppHost() to configure the Hono application, then passes the result to startServerHost(), which hands it to Bun.serve() and manages the process lifecycle.

  • App host (app-host.ts) - owns the application: what middleware runs, which routes and endpoint groups are mounted, what the API looks like.
  • Server host (server-host.ts) - owns the server: which port it listens on, how it shuts down on process signals.
  • main.ts - wires them together; the natural place to compose the application.
// main.ts
const appHost = createAppHost<AppEnv>({
    basePath: env.BASE_PATH,
    logging: { logLevel: env.LOG_LEVEL },
    exposeOpenApi: env.EXPOSE_OPENAPI,
    endpointGroups: [myRoutes],
});

startServerHost({ port: env.PORT, appHost });

src/env.ts

Validates and exports the server configuration from environment variables using Zod. Parsed once at startup — if any required variable fails validation, the process exits with an error.

Variable Type Default Description
NODE_ENV development | production | test development Runtime environment
PORT number 7200 Port the server listens on
BASE_PATH string (optional) Base path prefix for all routes (e.g. api)
LOG_LEVEL LogLevel name WARNING Global log level
LOG_LEVEL__<scope> LogLevel name Per-scope log level override; one variable per scope (e.g. LOG_LEVEL__request=TRACE)
EXPOSE_OPENAPI true | 1 | anything else false Whether to register OpenAPI spec and Scalar UI endpoints

LOG_LEVEL and LOG_LEVEL__<scope> accept the LogLevel enum member names: NONE, ERROR, WARNING, INFO, TRACE.

The generated .env.development file provides sensible defaults for local development:

PORT=7200
BASE_PATH=
EXPOSE_OPENAPI=true
LOG_LEVEL=WARNING
LOG_LEVEL__request=TRACE

Two exports are available for use in main.ts:

  • env — the validated config object
  • getLogLevelPerScope() — reads all LOG_LEVEL__<scope> variables and returns a Record<string, LogLevel>

src/app-host.ts

createAppHost(options) constructs and returns a configured Hono<AppEnv> instance.

Built-in middleware pipeline (applied in this order):

Middleware Purpose
Logging Attaches a scoped, leveled log function factory to c.var.getLogFunction
requestId Attaches a unique request ID to c.var.requestId
RequestLogger Logs method and path at TRACE level using the request scope
compress Gzip/Brotli response compression
secureHeaders Adds security response headers

Built-in endpoints:

Path Description
/health Returns ok with status 200
/buildinfo Returns the contents of buildinfo.txt
/<openApiPath> OpenAPI JSON spec (default path: openapi)
/<openApiUiPath> Scalar API reference UI (default path: scalar)

Options:

type AppHostOptions<E extends Env> = {
    basePath?: string;                   // base path prefix for all routes
    logging: LoggingOptions;             // log level configuration; see Logging middleware
    exposeOpenApi: boolean;              // whether to register OpenAPI spec and Scalar UI endpoints
    middleware?: MiddlewareHandler<E>[];  // additional middleware, applied after built-ins
    endpointGroups?: Hono<E>[];          // Hono sub-apps mounted at '/'
    openApi?: {
        path?: string;                   // OpenAPI spec path (default: 'openapi')
        uiPath?: string;                 // Scalar UI path (default: 'scalar')
        title?: string;
        description?: string;
    };
}

AppEnv

export interface AppEnv extends Env {
    Variables: LoggingVariables
}

Extends Hono's Env with LoggingVariables, making c.var.getLogFunction and c.var.requestId available throughout. Exported to be extended when additional context variables are needed:

interface MyEnv extends AppEnv {
    Variables: AppEnv['Variables'] & {
        user: User;
    }
}

const appHost = createAppHost<MyEnv>({ ... });

const myRoutes = new Hono<MyEnv>();
myRoutes.get('/profile', (c) => c.json(c.var.user));

Adding endpoints

const myRoutes = new Hono<AppEnv>();
myRoutes.get('/items', (c) => c.json({ items: [] }));

const appHost = createAppHost<AppEnv>({
    endpointGroups: [myRoutes],
});

Mounting a SPA

Pass a createSpa() result directly as an endpoint group. See @temir.ra/create-hono-spa for details.

import { createSpa } from '@scope/my-spa/spa';

const appHost = createAppHost<AppEnv>({
    basePath: 'api/',
    endpointGroups: [createSpa({ basePath: 'api' })],
});

src/server-host.ts

startServerHost(options) wraps Bun.serve() and registers SIGINT/SIGTERM handlers for graceful shutdown.

type ServerHostOptions = {
    port: number;
    appHost: Hono<AppEnv>;
    stopCallback?: (server: Bun.Server<undefined>) => void;
}

On SIGINT or SIGTERM: calls stopCallback (if provided), stops the Bun server, then exits with code 0.

src/middleware/logging/

Logging(options)

Attaches a getLogFunction(scope?) factory to the request context as c.var.getLogFunction. Call it in any handler or middleware to get a scoped log function:

const log = c.var.getLogFunction('my-scope');
log(LogLevel.INFO, 'Processing request', { id });

Log output format: [<ISO timestamp>] [<requestId>] [<scope>] [<LEVEL>] <message>

Options:

type LoggingOptions = {
    logLevel: LogLevel;                          // global default level
    logLevelPerScope?: Record<string, LogLevel>; // per-scope overrides
}

LogLevel enum: NONE | ERROR | WARNING | INFO | TRACE

The generated .env.development configures WARNING globally and TRACE for the request scope.

RequestLogger()

Logs <status> <METHOD> <duration>ms <path>[?<query>] at TRACE level using the request scope. Applied after requestId and Logging so all three are available. Duration is measured from when the middleware is entered to when the response is sent.

DevOps

bun update
bun install

bun run clean
bun run build
bun run tests

# see publish section for publish instructions

Change Management

  1. Create a new branch for the change.
  2. Make the changes and commit.
  3. Bump the version in package.json.
  4. Add an entry for the new version in CHANGELOG.md.
  5. Pull request the branch.
  6. Ensure package artifacts are current.
  7. Publish.

Publish

Publish to the public npm registry.

# authenticate
npm login
# publish
bun publish --registry https://registry.npmjs.org/ --access public