Server Entry File

The server entry file defines your application's routing, middleware, and configuration for the CLI.

What is UserServerEntry?

UserServerEntry is the type for the object you export from your server entry file. It combines:

  • Routing configuration (routes, fetch, middleware, error)
  • Server options (including runtime-specific options like bun, deno, node)
export type UserServerEntry = ServerOptions & RoutingOptions

Basic Example

// server.ts
export default {
  port: 3000,
  routes: {
    "/": () => new Response("Hello World"),
    "/api/users": {
      GET: () => new Response("List users"),
      POST: () => new Response("Create user"),
    },
  },
  fetch: () => new Response("Not Found", { status: 404 }),
};

Export Formats

The CLI supports two main export formats:

1. Default Export (Object)

Export all configuration as a single default object:

// server.ts
export default {
  port: 3000,
  routes: {
    "/": () => new Response("Hello"),
  },
  fetch: () => new Response("Not Found", { status: 404 }),
  middleware: [],
};

2. Named Exports

Export each configuration field separately:

// server.ts
export const port = 3000;

export const routes = {
  "/": () => new Response("Hello"),
};

export const fetch = () => new Response("Not Found", { status: 404 });

export const middleware = [];

Both formats are equivalent. The CLI automatically detects and normalizes them.

Available Fields

Routing Configuration

routes

Declarative route table matched before the fallback fetch handler.

export default {
  routes: {
    "/": () => new Response("Home"),
    "/about": () => new Response("About"),
    "/api/*": () => new Response("API"),
  },
};

fetch

Fallback request handler for unmatched routes.

export default {
  routes: {
    "/": () => new Response("Home"),
  },
  fetch: () => new Response("Not Found", { status: 404 }),
};

middleware

Global middleware array executed before handlers.

import { log } from "sevok/log";

export default {
  middleware: [log()],
  fetch: () => new Response("ok"),
};

middlewareResolver

Resolver for named middleware entries.

export default {
  middleware: ["auth", "cache"],
  middlewareResolver: (name) => {
    if (name === "auth") return async (ctx, next) => next(ctx);
    if (name === "cache") return async (ctx, next) => next(ctx);
  },
  fetch: () => new Response("ok"),
};

error

Error handler for request processing failures.

export default {
  error: (error) => {
    console.error(error);
    return new Response("Internal Server Error", { status: 500 });
  },
  fetch: () => new Response("ok"),
};

Server Options

port

Listening port (default: PORT env or 3000).

export default {
  port: 8080,
  fetch: () => new Response("ok"),
};

hostname

Listening host (default: HOST env or all interfaces).

export default {
  hostname: "127.0.0.1",
  fetch: () => new Response("ok"),
};

reusePort

Allow multiple processes to bind the same port.

export default {
  reusePort: true,
  fetch: () => new Response("ok"),
};

protocol

Use "http" or "https".

export default {
  protocol: "https",
  tls: {
    cert: "./cert.pem",
    key: "./key.pem",
  },
  fetch: () => new Response("ok"),
};

tls

TLS certificate configuration.

export default {
  tls: {
    cert: "./certs/cert.pem",
    key: "./certs/key.pem",
    passphrase: "secret",
  },
  fetch: () => new Response("ok"),
};

silent

Disable startup logging.

export default {
  silent: true,
  fetch: () => new Response("ok"),
};

gracefulShutdown

Enable graceful shutdown on SIGINT/SIGTERM.

export default {
  gracefulShutdown: true,
  fetch: () => new Response("ok"),
};

Or with custom timeouts:

export default {
  gracefulShutdown: {
    gracefulTimeout: 10,
    forceTimeout: 5,
  },
  fetch: () => new Response("ok"),
};

manual

Prevent automatic server start (useful for testing).

export default {
  manual: true,
  fetch: () => new Response("ok"),
};

Runtime-Specific Options

bun

Bun-specific options merged into Bun.serve().

export default {
  bun: {
    idleTimeout: 10,
    development: false,
  },
  fetch: () => new Response("ok"),
};

See Bun.serve options for available fields.

deno

Deno-specific options merged into Deno.serve().

export default {
  deno: {
    signal: AbortSignal.timeout(30_000),
    onListen: (info) => console.log(`Listening on ${info.hostname}:${info.port}`),
  },
  fetch: () => new Response("ok"),
};

See Deno.ServeOptions for available fields.

node

Node.js-specific options including HTTP/HTTPS/HTTP2 server options.

export default {
  node: {
    http2: true,
    requestTimeout: 30_000,
    onError: (error) => {
      console.error(error);
      return new Response("Error", { status: 500 });
    },
  },
  fetch: () => new Response("ok"),
};

Available fields:

  • Standard Node.js server options (requestTimeout, keepAliveTimeout, etc.)
  • http2: Enable HTTP/2 (requires TLS)
  • onError: Custom error handler for Node.js adapter

Complete Example

Using Default Export

// server.ts
import { log } from "sevok/log";
import { serveStatic } from "sevok/static";

export default {
  port: 3000,
  hostname: "127.0.0.1",
  gracefulShutdown: true,

  middleware: [
    log(),
    serveStatic({ dir: "./public" }),
  ],

  routes: {
    "/": () => new Response("Home"),
    "/api/users": {
      GET: () => new Response("List users"),
      POST: () => new Response("Create user"),
    },
    "/api/users/:id": {
      GET: (ctx) => new Response(`User ${ctx.params.id}`),
      PUT: (ctx) => new Response(`Update user ${ctx.params.id}`),
      DELETE: (ctx) => new Response(`Delete user ${ctx.params.id}`),
    },
  },

  fetch: () => new Response("Not Found", { status: 404 }),

  error: (error) => {
    console.error(error);
    return new Response("Internal Server Error", { status: 500 });
  },
};

Using Named Exports

// server.ts
import { log } from "sevok/log";
import { serveStatic } from "sevok/static";

export const port = 3000;
export const hostname = "127.0.0.1";
export const gracefulShutdown = true;

export const middleware = [
  log(),
  serveStatic({ dir: "./public" }),
];

export const routes = {
  "/": () => new Response("Home"),
  "/api/users": {
    GET: () => new Response("List users"),
    POST: () => new Response("Create user"),
  },
  "/api/users/:id": {
    GET: (ctx) => new Response(`User ${ctx.params.id}`),
    PUT: (ctx) => new Response(`Update user ${ctx.params.id}`),
    DELETE: (ctx) => new Response(`Delete user ${ctx.params.id}`),
  },
};

export const fetch = () => new Response("Not Found", { status: 404 });

export const error = (error: unknown) => {
  console.error(error);
  return new Response("Internal Server Error", { status: 500 });
};

Notes

  • The CLI automatically injects logging and static file middleware
  • Use --prod flag to disable watch mode and enable production defaults