# How the Kaneo API Is Structured Within the Monorepo: A Layered Hono Architecture

> Discover the layered Hono architecture of the Kaneo API within its monorepo. Explore modular design, hierarchical routing, and Drizzle ORM integration for efficient development.

- Repository: [kaneo.app/kaneo](https://github.com/usekaneo/kaneo)
- Tags: architecture
- Published: 2026-08-09

---

**The Kaneo API is organized as a modular Hono application under `apps/api/src`, using a hierarchical router pattern that separates global middleware, domain-specific feature routers, and pure-function controllers interacting with Drizzle ORM.**

The Kaneo project (`usekaneo/kaneo`) implements a clean, scalable backend architecture within its Turborepo-based monorepo. The API layer follows a strict separation of concerns: a thin root application handles cross-cutting concerns like CORS and authentication, while feature-specific modules own their own routing and business logic. This design enables independent development of domains such as tasks, comments, and workspaces without coupling to the core application bootstrap.

## Root Application and Global Middleware

The entry point for the API is **[`apps/api/src/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/index.ts)**, which exports a `createApp()` function. This factory instantiates a top-level `Hono<AppVariables>()` instance and installs global middleware before any routes are mounted.

According to the source code, the root app configures:

- **CORS** handling for cross-origin requests
- **Error handling** wrappers for consistent JSON error responses
- **WebSocket adapter** setup for upgrade handling
- **Authentication middleware** (`authenticateApiRequest`) applied globally

The root app then mounts the API sub-router using `app.route("/api", api)`, creating the `/api` path prefix that all public endpoints share.

## The API Sub-Router Pattern

Within [`apps/api/src/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/index.ts), a dedicated `api` router is instantiated as `new Hono<ApiVariables>()`. This sub-router acts as a collector for all domain-specific routes and exposes several meta-endpoints:

- Health check endpoints for monitoring
- Asset download routes for file serving
- The OpenAPI specification at `/api/openapi`

The API router applies authentication middleware to all its routes via `api.use("*", async (c, next) => { await authenticateApiRequest(c); ... })`, ensuring every request is validated before reaching feature handlers.

## Feature-Based Router Architecture

Each business domain (comment, task, project, workspace) lives in its own directory under `apps/api/src/`, following a consistent pattern. For example, the comment module is defined in **[`apps/api/src/comment/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/comment/index.ts)**, which exports a Hono router instance configured with CRUD operations.

Feature routers are mounted onto the API router in the main index file:

```typescript
// apps/api/src/index.ts (excerpt)
import comment from "./comment";
import task from "./task";
import project from "./project";

api.route("/comment", comment);
api.route("/task", task);
api.route("/project", project);

```

Each feature router uses **`hono-openapi`** decorators for automatic documentation generation. The router in [`apps/api/src/comment/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/comment/index.ts) demonstrates this pattern by combining route definitions with `describeRoute()`, `validator()` (using Valibot schemas), and resolver utilities to produce type-safe, documented endpoints.

## Controller Layer and Database Access

Controllers are pure functions stored in `controllers/` subdirectories within each feature folder. They encapsulate all database interactions using **Drizzle ORM** and return plain data objects.

For instance, **[`apps/api/src/comment/controllers/create-comment.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/comment/controllers/create-comment.ts)** handles the insertion logic, importing schema definitions from **[`apps/api/src/database/schema.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/database/schema.ts)**. This separation ensures that routers remain thin—responsible only for HTTP concerns like validation and serialization—while controllers manage business logic and data persistence.

```typescript
// apps/api/src/comment/index.ts (pattern example)
import { Hono } from "hono";
import { describeRoute, validator } from "hono-openapi";
import * as v from "valibot";
import createComment from "./controllers/create-comment";

const comment = new Hono()
  .post(
    "/",
    describeRoute({ operationId: "createComment", tags: ["Comment"] }),
    validator("json", v.object({ content: v.string(), taskId: v.string() })),
    async (c) => {
      const body = c.req.valid("json");
      const result = await createComment(body);
      return c.json(result, 201);
    }
  );

export default comment;

```

## Authentication and Shared Utilities

The **[`apps/api/src/utils/authenticate-api-request.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/utils/authenticate-api-request.ts)** file exports the central authentication middleware used across the API. This utility validates session tokens or API keys extracted from the `Authorization` header and populates the Hono context with user and workspace information.

Additional utilities handle workspace validation, asset streaming, and OpenAPI normalization. These helpers are imported by feature routers as needed, maintaining DRY principles while keeping the root application configuration uncluttered.

## WebSocket Support

Real-time functionality is handled by a separate sub-router defined in **[`apps/api/src/ws/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/index.ts)**. This router manages HTTP upgrade requests to WebSocket connections under the `/ws/*` path.

The WebSocket layer reuses the same `authenticateApiRequest` middleware to validate connections before upgrading, ensuring that real-time channels respect the same security boundaries as the REST API.

## OpenAPI Integration

The API automatically generates an OpenAPI 3.0 specification by traversing the decorated routes. The `openAPIRouteHandler` (referenced in the main index) merges route metadata from all feature routers and serves the combined spec at `/api/openapi`.

This integration means that adding `describeRoute()` metadata to a new endpoint immediately updates the public API documentation without manual YAML maintenance.

## Summary

- The **root app** in [`apps/api/src/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/index.ts) bootstraps the Hono instance and configures global middleware including CORS and authentication.
- An **API sub-router** mounted at `/api` collects all domain routes and provides health checks and OpenAPI serving.
- **Feature routers** (e.g., `comment`, `task`, `project`) live in dedicated directories and define their own CRUD endpoints using `hono-openapi` for documentation.
- **Controllers** are pure functions that interact with the database via Drizzle ORM, keeping routers focused on HTTP layer concerns.
- **Shared utilities** like `authenticateApiRequest` enforce security consistently across both REST and WebSocket interfaces.
- The **WebSocket router** at `/ws` handles real-time connections using the same authentication flow as the main API.

## Frequently Asked Questions

### What framework powers the Kaneo API?

The Kaneo API is built on **Hono**, a lightweight, edge-compatible web framework. It uses Hono's router composition features to create a hierarchical structure where the root app mounts sub-routers for the API namespace and individual features.

### How does authentication work across all API routes?

Authentication is enforced by the `authenticateApiRequest` middleware defined in [`apps/api/src/utils/authenticate-api-request.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/utils/authenticate-api-request.ts). This middleware is attached to the API router with `api.use("*", ...)` in [`apps/api/src/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/index.ts), ensuring every request—including those to feature routers—validates session tokens or API keys before executing handlers.

### Where should new endpoints be added when extending the API?

New features should follow the existing pattern: create a directory under `apps/api/src/` (e.g., `apps/api/src/feature-name/`), add an [`index.ts`](https://github.com/usekaneo/kaneo/blob/main/index.ts) that exports a Hono router with your routes, and import this router into [`apps/api/src/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/index.ts) to mount it via `api.route("/feature-name", featureName)`. Controllers should be placed in a `controllers/` subdirectory within your feature folder.

### How does the API handle real-time communication?

Real-time functionality is provided by a dedicated WebSocket sub-router in [`apps/api/src/ws/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/index.ts). This router handles HTTP upgrade requests at `/ws/*` paths and uses the same `authenticateApiRequest` middleware to secure connections before establishing the WebSocket channel, ensuring parity with the REST API's security model.