# How Does the Karakeep Backend Communicate with the Frontend?

> Discover how the Karakeep backend communicates with its frontend. Learn about the tRPC API, Hono server, appRouter, and Next.js client integration for seamless data flow.

- Repository: [Karakeep App/karakeep](https://github.com/karakeep-app/karakeep)
- Tags: architecture
- Published: 2026-07-07

---

**Karakeep uses a type-safe tRPC-based HTTP API running on a Hono server, where the backend exposes domain logic through a centralized `appRouter` mounted at `/api/trpc`, and the Next.js frontend consumes these procedures using a batched tRPC client integrated with React Query.**

Karakeep is an open-source bookmarking application that prioritizes developer experience through end-to-end type safety. Understanding how the Karakeep backend communicates with the frontend reveals a modern architecture built on tRPC, Hono, and React Query that eliminates API contract mismatches and reduces network overhead through automatic request batching.

## Backend Architecture: The tRPC Router and Hono Server

The backend exposes all domain logic through a single tRPC router that aggregates feature-specific sub-routers.

### The Centralized `appRouter`

In [`packages/trpc/routers/_app.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/trpc/routers/_app.ts), the application defines a root router that composes all feature modules:

```typescript
import { router } from "../index";
// ... other imports

export const appRouter = router({
  bookmarks: bookmarksAppRouter,
  apiKeys: apiKeysAppRouter,
  users: usersAppRouter,
  // ... other feature routers
});

export type AppRouter = typeof appRouter;

```

This `appRouter` serves as the single entry point for all API calls. The export of `AppRouter` type is critical—it provides the TypeScript definition that the frontend uses to guarantee procedure names and input/output types match exactly between client and server.

### Hono Server Integration

The tRPC router is mounted on a Hono HTTP server (see [`apps/api/src/server.ts`](https://github.com/karakeep-app/karakeep/blob/main/apps/api/src/server.ts)), creating the actual HTTP endpoint at `/api/trpc`. Hono handles the underlying HTTP layer including middleware, while tRPC manages request validation, type-safe routing, and error handling. When requests hit `/api/trpc/*`, Hono forwards them to the tRPC handler which dispatches to the appropriate procedure in the `appRouter`.

## Frontend Integration: Next.js and React Query

The frontend consumes the backend API through a tRPC client configured with performance optimizations.

### Client Initialization with `httpBatchLink`

The frontend creates a tRPC client in [`packages/sdk/src/trpc.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/sdk/src/trpc.ts) using `httpBatchLink` to enable request batching:

```typescript
import { createTRPCClient, httpBatchLink } from "@trpc/client";
import type { AppRouter } from "@karakeep/trpc/routers/_app";

export const trpc = createTRPCClient<AppRouter>({
  links: [
    httpBatchLink({
      url: "/api/trpc", // Relative path works in production
    }),
  ],
});

```

This configuration, also illustrated in [`tools/seed-snapshot/src/index.ts`](https://github.com/karakeep-app/karakeep/blob/main/tools/seed-snapshot/src/index.ts), allows multiple simultaneous procedure calls (like `bookmarks.list` and `users.me`) to be bundled into a single HTTP request, significantly reducing network chatter.

### React Query Integration

The client is wired into TanStack React Query (see [`packages/sdk/src/react-query.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/sdk/src/react-query.ts)) for caching and automatic refetching. Components call procedures using standard React Query hooks:

```tsx
import { useQuery } from "@tanstack/react-query";
import { trpc } from "@/trpc";

export const BookmarkList = () => {
  const { data, isLoading } = useQuery(
    ["bookmarks"],
    () => trpc.bookmarks.list.query()
  );

  if (isLoading) return <p>Loading…</p>;
  return (
    <ul>
      {data?.map(b => (
        <li key={b.id}>{b.title}</li>
      ))}
    </ul>
  );
};

```

## Data Flow and Type Safety

When a component invokes a procedure like `trpc.bookmarks.list.query()`, the following sequence occurs:

1. **Serialization**: The tRPC client serializes the procedure name and input parameters.
2. **Batching**: If multiple calls occur simultaneously, `httpBatchLink` bundles them into one HTTP POST request to `/api/trpc`.
3. **Server Handling**: Hono receives the request and forwards it to the tRPC handler, which routes to the appropriate procedure in `appRouter`.
4. **Execution**: The procedure executes the domain logic (e.g., querying the database for bookmarks).
5. **Response**: Results return as JSON, React Query updates its cache, and the UI re-renders with fresh data.

This architecture provides **end-to-end type safety** because the same TypeScript types define both the server procedures and client calls, eliminating the possibility of API drift or contract mismatches.

## Key Implementation Files

- **[`packages/trpc/routers/_app.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/trpc/routers/_app.ts)**: Defines the central `appRouter` that aggregates all feature routers (bookmarks, users, apiKeys).
- **[`packages/sdk/src/trpc.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/sdk/src/trpc.ts)**: Exports the configured tRPC client used throughout the web application.
- **[`packages/sdk/src/react-query.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/sdk/src/react-query.ts)**: Bridges tRPC calls with TanStack React Query for caching and state management.
- **[`apps/api/src/server.ts`](https://github.com/karakeep-app/karakeep/blob/main/apps/api/src/server.ts)**: Mounts the tRPC router on the Hono server at the `/api/trpc` endpoint.
- **[`tools/seed-snapshot/src/index.ts`](https://github.com/karakeep-app/karakeep/blob/main/tools/seed-snapshot/src/index.ts)**: Reference implementation showing client setup with `httpBatchLink`.

## Summary

- **tRPC on Hono**: The backend exposes a type-safe API via an `appRouter` mounted at `/api/trpc` using Hono as the HTTP server.
- **Batched Client**: The frontend uses `createTRPCClient` with `httpBatchLink` to bundle multiple requests into single HTTP calls for efficiency.
- **React Query Bridge**: tRPC integrates with TanStack React Query ([`packages/sdk/src/react-query.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/sdk/src/react-query.ts)) to provide caching, background refetching, and optimistic updates.
- **Zero-Contract Risks**: Shared TypeScript types between [`packages/trpc/routers/_app.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/trpc/routers/_app.ts) and the frontend SDK ensure compile-time guarantees for API inputs and outputs.

## Frequently Asked Questions

### What protocol does Karakeep use for frontend-backend communication?

Karakeep uses **HTTP with tRPC** as the application protocol. While the transport is standard HTTP POST requests to `/api/trpc`, tRPC handles the RPC layer, providing type-safe procedure calls over the wire instead of traditional REST endpoints.

### How does Karakeep maintain type safety across the API boundary?

Type safety is enforced by importing the `AppRouter` type from [`packages/trpc/routers/_app.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/trpc/routers/_app.ts) into the frontend client initialization. This single source of truth ensures that if a procedure name changes or an input schema is modified on the backend, TypeScript compilation on the frontend will fail immediately, preventing runtime errors.

### Why does Karakeep use request batching for API calls?

The frontend configures `httpBatchLink` to automatically batch multiple simultaneous tRPC procedure calls into a single HTTP request. This reduces network overhead and improves performance when components make several data requests at once, such as during initial page loads.

### Where is the tRPC router defined in the Karakeep codebase?

The main router is defined in [`packages/trpc/routers/_app.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/trpc/routers/_app.ts) as the `appRouter` constant. This file imports and combines sub-routers (like `bookmarksAppRouter`, `usersAppRouter`) into a single unified router that represents the entire backend API surface.