# Kaneo Monorepo Structure Explained: Apps, Packages, and Shared Libraries

> Explore the Kaneo monorepo structure. Learn how apps, packages, and shared libraries are organized in TypeScript for clean separation and efficient development.

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

---

**Kaneo uses a TypeScript-based "apps + packages" monorepo that isolates the API server, React frontend, documentation, and shared libraries into distinct directories for clean separation of concerns.**

Kaneo is an open-source project management platform built as a modern JavaScript monorepo. Understanding its directory layout helps developers navigate the codebase, contribute effectively, and extend the platform. This guide breaks down the Kaneo monorepo structure based on the actual source code in `usekaneo/kaneo`.

## The Apps + Packages Pattern

The Kaneo monorepo follows the standard pattern used by tools like Turborepo and Nx. Code is organized into two main categories:

- **Apps (`apps/*`)** — Complete, runnable applications that can be deployed independently
- **Packages (`packages/*`)** — Reusable libraries imported by apps and other packages

This structure prevents code duplication while maintaining clear boundaries between deployable units.

## Top-Level Directory Overview

| Directory | Purpose |
|-----------|---------|
| `apps/api` | Hono-based HTTP API with WebSockets and database access |
| `apps/web` | React/Vite frontend for boards, tasks, and UI state |
| `apps/docs` | Markdown documentation source files |
| `apps/site` | Next.js public site for marketing and docs |
| `packages/libs` | Typed API client shared across consumers |
| `packages/permissions` | Workspace-scoped authorization definitions |
| `packages/mcp` | MCP command-line interface package |
| `tests/api` | Backend unit and integration tests |
| `i18n/` | Localization files (e.g., [`en-US.json`](https://github.com/usekaneo/kaneo/blob/main/en-US.json)) |
| `deploy/` | Docker entrypoints and container assets |
| `charts/kaneo` | Helm chart for Kubernetes deployment |
| `plans/` | Architectural design documents |

## The API Application (`apps/api`)

The backend is a **Hono server** that handles HTTP requests, WebSocket connections, and database operations.

Key locations in `apps/api/src/`:

- [`openapi.ts`](https://github.com/usekaneo/kaneo/blob/main/openapi.ts) — Route registration and OpenAPI metadata
- [`database/schema.ts`](https://github.com/usekaneo/kaneo/blob/main/database/schema.ts) — PostgreSQL schema definitions
- `**/controllers/` — Business logic handlers
- `ws/` — WebSocket adapters for real-time updates
- `mcp/` — MCP tooling integration

Authentication, event handling, and workspace isolation are all implemented here.

## The Web Application (`apps/web`)

The frontend is a **React application built with Vite** that consumes typed API calls.

Key locations in `apps/web/src/`:

- `**/components/` — React UI components
- `hooks/` — Custom hooks including permission checks and WebSocket handlers
- `fetchers/` — Client utilities for data fetching

The frontend does not call the API directly. Instead, it imports the typed client from `packages/libs` for full TypeScript safety.

## Shared Libraries (`packages/*`)

### `packages/libs`: The Typed Client

This package exports a **type-safe HTTP client** that both `apps/web` and external consumers use.

```typescript
import { createKaneoClient } from '@kaneo/libs/client';

const client = createKaneoClient({ baseUrl: '/api' });

// Type-safe API call with autocomplete
const projects = await client.project.list({ workspaceId: 'w_123' });

```

The client ensures frontend and backend types stay synchronized.

### `packages/permissions`: Authorization

Canonical permission definitions enforce workspace-scoped access control.

```typescript
import { requireWorkspacePermission } from '@kaneo/permissions';

export async function createTask(ctx: Ctx) {
  await requireWorkspacePermission(ctx, 'task:create');
  // Proceed with controller logic...
}

```

Both the API and frontend import from this package to maintain consistent permission checks.

### `packages/mcp`: Command-Line Interface

Implements the **MCP (standard I/O)** protocol for CLI interactions with the Kaneo server.

## Data Flow Through the Monorepo

```

Browser (apps/web)
    ↓
Typed Client (packages/libs)
    ↓
Hono API (apps/api)
    ↓
PostgreSQL

```

Real-time updates reverse part of this flow: the API's WebSocket layer (`apps/api/src/ws`) pushes events to React hooks (`apps/web/src/hooks/use-*`).

## Testing and Deployment

Tests are **co-located by concern**:

- `tests/api` and `tests/api-integration` cover backend logic
- Frontend tests live alongside components (`apps/web/src/**/*.test.tsx`)

Deployment artifacts at the root enable consistent environments:

- [`compose.yml`](https://github.com/usekaneo/kaneo/blob/main/compose.yml) — Docker Compose for local development
- `deploy/` — Production container scripts
- `charts/kaneo/` — Helm chart for Kubernetes

## Key Files That Define the Structure

| File | Role |
|------|------|
| [`apps/api/src/openapi.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/openapi.ts) | Hono route registration |
| [`apps/api/src/database/schema.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/database/schema.ts) | Database schema source |
| [`apps/web/src/hooks/use-workspace-permission.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/hooks/use-workspace-permission.ts) | Frontend permission checking |
| [`packages/libs/src/client.ts`](https://github.com/usekaneo/kaneo/blob/main/packages/libs/src/client.ts) | Typed client implementation |
| [`packages/permissions/src/middleware.ts`](https://github.com/usekaneo/kaneo/blob/main/packages/permissions/src/middleware.ts) | API permission enforcement |
| [`compose.yml`](https://github.com/usekaneo/kaneo/blob/main/compose.yml) | Local development orchestration |

These files illustrate how concerns are separated: API logic, UI logic, shared types, and cross-cutting permissions each have dedicated, importable locations.

## Real-Time Updates Example

Subscribing to WebSocket events in a React hook:

```tsx
import { useProjectWebsocket } from '@/hooks/use-project-websocket';

export function useProjectUpdates(projectId: string) {
  const ws = useProjectWebsocket(projectId);

  useEffect(() => {
    const handler = (event: MessageEvent) => {
      // Update local state with server event
    };
    ws.addEventListener('message', handler);
    return () => ws.removeEventListener('message', handler);
  }, [ws]);
}

```

## Summary

- **Apps (`apps/*`)** contain deployable units: API server, web UI, docs, and marketing site
- **Packages (`packages/*`)** provide shared, versioned libraries: typed client, permissions, and MCP tooling
- **Type safety** is enforced across boundaries via `packages/libs`
- **Workspace-scoped permissions** are centralized in `packages/permissions`
- **Testing** is organized by layer with backend suites in `tests/` and frontend tests co-located
- **Deployment** uses Docker and Helm with configuration at the repository root

## Frequently Asked Questions

### What monorepo tool does Kaneo use?

Kaneo follows the standard "apps + packages" convention common to Turborepo, Nx, and pnpm workspaces. The repository structure uses workspace-level dependencies to link `packages/*` into `apps/*` without publishing to npm.

### How does the frontend stay type-safe with the API?

The frontend imports `createKaneoClient` from `packages/libs`, which exposes methods with TypeScript types derived from the API's OpenAPI specification. This guarantees that request parameters and response shapes match the actual server implementation.

### Where are database migrations and schema defined?

Database schema lives in [`apps/api/src/database/schema.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/database/schema.ts). The API application owns all data persistence logic; no other app or package directly accesses the database.

### Can I deploy the API and web frontend separately?

Yes. `apps/api` and `apps/web` are independent deployable units. The API can run without the frontend, and the frontend can be built as static files or served through `apps/site` (Next.js) depending on your hosting requirements.