Oak Middleware Framework Documentation

repository·main·Indexed Apr 15, 2026

https://github.com/oakserver/oak

Oak is a middleware framework for HTTP servers inspired by Koa, supporting Deno, Node.js, Cloudflare Workers, and Bun. It provides a robust middleware router and handles HTTP request/response cycles through a context-based architecture. Documentation covers deployment to Deno Deploy, URL component access via ctx.request.url, server lifecycle management with AbortController, redirects, state sharing, middleware execution flow, SSE support, and testing utilities.

Tokens
35.1K
Snippets
91
Records
138
Agent score
90%

What's inside oak

  1. Install oak

    main
    Oak is a middleware framework for HTTP servers. It supports Deno, Node.js, Cloudflare Workers, and Bun.
  2. Enable Server-Sent Events (SSE) in Oak

    main

    Oak provides built-in support for Server-Sent Events (SSE), a one-way communication protocol. To use SSE, call ctx.sendEvents() within a route handler to establish a connection and obtain a ServerSentEventTarget.

    Basic Usage

    import { Application, Router } from "https://deno.land/x/oak/mod.ts";
    
    const app = new Application();
    const router = new Router();
    
    router.get("/sse", async (ctx) => {
      const target = await ctx.sendEvents();
      target.dispatchMessage({ hello: "world" });
    });
    
    app.use(router.routes());
    await app.listen({ port: 80 });

    Handling Connection Close

    You can detect when the client closes the connection by listening for the close event on the target:

    router.get("/sse", async (ctx) => {
      const target = await ctx.sendEvents();
      target.addEventListener("close", (evt) => {
        // perform cleanup activities
      });
      target.dispatchMessage({ hello: "world" });
    });

    Closing the Connection from Server

    To close the connection from the server side, await the close() method on the target:

    router.get("/sse", async (ctx) => {
      const target = await ctx.sendEvents();
      target.dispatchMessage({ hello: "world" });
      await target.close();
    });

    Sending Custom Events

    Use ServerSentEvent to send named events. These are dispatched as MessageEvent on the client side.

    router.get("/sse", async (ctx: Context) => {
      const target = await ctx.sendEvents();
      const event = new ServerSentEvent("ping", { hello: "world" });
      target.dispatchEvent(event);
    });

    On the client side:

    const source = new EventSource("/sse");
    source.addEventListener("ping", (evt) => {
      console.log(evt.data); // logs string: '{"hello":"world"}'
    });

    Dispatching Messages and Comments

    • target.dispatchMessage(data): Sends a data-only message. The client receives this via source.onmessage with type "message".
    • target.dispatchComment(comment): Sends a comment to the client. This does not trigger an event on the client but can be used for debugging or keeping the connection alive.

    Cancellable Events

    Events dispatched on the server can be cancelled before being sent to the client. If an event listener calls .preventDefault() on the event, the event will not be sent to the client.

    Sources: docs/sse.md

  3. Via JSR

    main

    Install the package:

    npx jsr i @oak/oak

    Import in your module:

    import { Application } from "@oakserver/oak/application";
  4. Create a Mock Application

    main

    Use testing.createMockApp() to create a mock Application instance for testing purposes. This is useful when your middleware depends on application-level properties or state.

    Signature:

    const app = testing.createMockApp(state?: S);
    • state: Optional argument representing the application state.

    Usage:

    const app = testing.createMockApp({ key: "value" });
    const ctx = testing.createMockContext({ app });

    This mock application can be passed to createMockContext() to simulate a fully configured environment.

    Sources: docs/testing.md

  5. Generate TLS certificates for local Oak development

    main

    To generate TLS certificates for local development with Oak, create an OpenSSL configuration file (e.g., domains.txt) to define the certificate properties. This file specifies the certificate type, usage, and subject alternative names (SANs) for the local domain.

    Use the following configuration content in your domains.txt file:

    authorityKeyIdentifier=keyid,issuer
    basicConstraints=CA:FALSE
    keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
    subjectAltName = @alt_names
    [alt_names]
    DNS.1 = localhost

    This configuration ensures the certificate is valid for localhost and includes the necessary key usage flags for TLS encryption. Refer to examples/tls/README.md for the full command to generate the certificate using this configuration file.

    Sources: examples/tls/domains.txt

  6. HTTPS Configuration

    main

    To serve over HTTPS, pass the secure, certFile, and keyFile options to app.listen():

    await app.listen({
      port: 8000,
      secure: true,
      certFile: "./cert.pem",
      keyFile: "./key.pem",
    });
    import { Application } from "@oak/oak/application";
    
    const app = new Application();
    
    app.use((ctx) => {
      ctx.response.body = "Hello World!";
    });
    
    await app.listen({ port: 8000 });

    Sources: README.md

  7. Share State Between Requests with app.state

    main

    The Application and Context share a .state object for passing custom data. By default, the application's state is cloned for each request, meaning changes to ctx.state do not persist across requests.

    Configuration: You can control state initialization behavior using the contextState option when creating the Application:

    • "clone" (default): Clones the app state, skipping non-cloneable values (functions, symbols).
    • "prototype": Uses app state as the prototype. Shallow assignments on ctx.state are local, but direct modifications affect the shared state.
    • "alias": ctx.state and app.state reference the same object.
    • "empty": Initializes ctx.state as an empty object.

    Example with TypeScript Generics:

    import { Application } from "https://deno.land/x/oak/mod.ts";
    
    interface MyState {
      userId: number;
    }
    
    const app = new Application<MyState>();
    
    app.use(async (ctx, next) => {
      // Set user ID
      ctx.state.userId = 123;
      await next();
      delete ctx.state.userId; // Cleanup
    });
    
    app.use(async (ctx, next) => {
      // Access user ID set by previous middleware
      console.log(ctx.state.userId);
      await next();
    });
    
    await app.listen();

    Sources: docs/FAQ.md

  8. Worker Configuration

    main
    Unlike Deno or Node.js, the Oak application does not listen for incoming requests. Instead, it handles fetch events. Export the fetch method directly.