# How to Set Up a Local Database for Karakeep Development

> Easily set up a local database for Karakeep development. Clone the repo, configure your .env file, and run a simple command to bootstrap and migrate your database.

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

---

**To set up a local database for Karakeep development, clone the `karakeep-app/karakeep` repository, install dependencies using `pnpm`, copy `.env.example` to `.env`, configure `DATABASE_URL` to point to a local SQLite file, and run `pnpm dev` to automatically bootstrap and migrate the database.**

Karakeep uses a **SQLite** database managed by **Drizzle ORM** to persist all user data, bookmarks, and metadata. This guide walks you through configuring a local development environment that mirrors production, whether you run the stack natively with Node.js or prefer containerized development with Docker Compose.

## Prerequisites

Before you begin, ensure your system meets the following requirements:

- **Node.js** version 20.x or higher
- **pnpm** version 9.x (the monorepo uses [`pnpm-workspace.yaml`](https://github.com/karakeep-app/karakeep/blob/main/pnpm-workspace.yaml) for dependency management)
- **Git** for cloning the repository
- *(Optional)* **Docker** and **Docker Compose** version 2.20+ if you prefer a containerized setup

## Step-by-Step Configuration

### Clone the Repository and Install Dependencies

Start by cloning the repository and installing all monorepo dependencies:

```bash
git clone https://github.com/karakeep-app/karakeep.git
cd karakeep
pnpm install

```

This installs the full dependency tree, including `better-sqlite3` and Drizzle ORM packages referenced in [[`packages/db/drizzle.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/db/drizzle.ts)](https://github.com/karakeep-app/karakeep/blob/main/packages/db/drizzle.ts).

### Configure Environment Variables

Create a local environment file from the provided template:

```bash
cp .env.example .env

```

Edit `.env` and set the `DATABASE_URL` variable to specify where the SQLite file should reside:

```bash

# .env

DATABASE_URL=sqlite://./dev.db

```

Karakeep parses this connection string in [[`packages/db/drizzle.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/db/drizzle.ts)](https://github.com/karakeep-app/karakeep/blob/main/packages/db/drizzle.ts) to instantiate the `better-sqlite3` driver. The path can be relative to the repository root or an absolute filesystem path.

### Initialize the Database

Run the development server to trigger automatic migration:

```bash
pnpm dev

```

On first startup, the application executes the `migrate()` function imported from [`drizzle-orm/better-sqlite3`](https://github.com/karakeep-app/karakeep/blob/main/packages/db/drizzle.ts), which applies all pending SQL migrations located in `packages/db/drizzle/*.sql`. You will see log output confirming the database is ready and the web server is listening on `http://localhost:3000`.

## Understanding the Database Architecture

### Drizzle ORM Bootstrap

The database connection is centralized in [[`packages/db/drizzle.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/db/drizzle.ts)](https://github.com/karakeep-app/karakeep/blob/main/packages/db/drizzle.ts). This file exports a singleton `db` object created via:

```typescript
import { drizzle } from "drizzle-orm/better-sqlite3";
import Database from "better-sqlite3";

const sqlite = new Database(process.env.DATABASE_URL!);
export const db = drizzle(sqlite, { schema });

```

This singleton is imported by all tRPC routers and background workers, ensuring every component speaks to the same SQLite file.

### Schema and Migrations

Table definitions reside in [[`packages/db/schema.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/db/schema.ts)](https://github.com/karakeep-app/karakeep/blob/main/packages/db/schema.ts), which provides the type-safe schema passed to the Drizzle client. Incremental migrations are stored as plain SQL files under `packages/db/drizzle/` (e.g., [`0084_rule_engine_multi_list_support.sql`](https://github.com/karakeep-app/karakeep/blob/main/0084_rule_engine_multi_list_support.sql)). The `migrate()` utility runs these scripts transactionally on startup, so you never need to manually execute SQL dumps.

## Optional: Docker Compose Development Stack

For a fully isolated environment that includes Meilisearch and background workers, use the provided development compose file:

```bash
docker compose -f docker/docker-compose.dev.yml up

```

The [[`docker/docker-compose.dev.yml`](https://github.com/karakeep-app/karakeep/blob/main/docker/docker-compose.dev.yml)](https://github.com/karakeep-app/karakeep/blob/main/docker/docker-compose.dev.yml) mounts your local SQLite file (as defined by `DATABASE_URL`) into the `web`, `workers`, and `api` services. This ensures data persists across container restarts while keeping the setup identical to native development.

## Verifying the Setup

### Access the Database Programmatically

You can query the database directly using the exported Drizzle client in any server-side context:

```typescript
// Example: Query bookmarks in a tRPC router
import { eq } from "drizzle-orm";
import { db } from "@karakeep/db/drizzle";
import { bookmarks } from "@karakeep/db/schema";

const userBookmarks = await db
  .select()
  .from(bookmarks)
  .where(eq(bookmarks.userId, "user-123"));

```

### Launch Drizzle Studio

To inspect tables and run ad-hoc queries via a web UI:

```bash
pnpm run db:studio

```

This command launches Drizzle Studio on `http://localhost:4000`, providing a visual interface to the same SQLite file defined in your `.env`.

## Troubleshooting Common Issues

- **`SQLITE_CANTOPEN` error on startup**: The directory path in `DATABASE_URL` does not exist or lacks write permissions. Ensure the parent directory exists and is writable by the Node.js process.
- **Migrations not applied**: An existing `dev.db` file was created before migration files were added. Delete the database file and restart `pnpm dev` to force a full migration run.
- **Type errors when importing `db`**: The `@karakeep/db` workspace alias is not linked. Run `pnpm install` again to regenerate monorepo symlinks.
- **Docker containers cannot find the database**: Verify that the volume mount in [`docker-compose.dev.yml`](https://github.com/karakeep-app/karakeep/blob/main/docker-compose.dev.yml) points to the same absolute path specified in your `.env` file.

## Summary

- Karakeep uses **SQLite** with **Drizzle ORM** for zero-configuration local development.
- Configure the database path via `DATABASE_URL` in `.env` (copied from `.env.example`).
- The `db` singleton exported from [[`packages/db/drizzle.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/db/drizzle.ts)](https://github.com/karakeep-app/karakeep/blob/main/packages/db/drizzle.ts) handles connections and automatic migrations.
- Run `pnpm dev` to bootstrap the database and start the development server.
- Use `pnpm run db:studio` to explore the schema and data via a web interface.
- Docker Compose provides an alternative setup with the same SQLite backing store.

## Frequently Asked Questions

### What database engine does Karakeep use for local development?

Karakeep uses **SQLite** via the `better-sqlite3` driver. The connection is managed by Drizzle ORM, which parses the `DATABASE_URL` environment variable to locate the `.db` file on disk. This eliminates the need for a separate PostgreSQL or MySQL server during development.

### How do I reset my local database to a clean state?

Delete the SQLite file specified in your `DATABASE_URL` (e.g., `rm ./dev.db`) and restart the application with `pnpm dev`. On restart, Drizzle will recreate the file and re-run all migrations from `packages/db/drizzle/*.sql`, giving you a fresh schema and empty tables.

### Can I use PostgreSQL instead of SQLite for local development?

While the production deployment can target PostgreSQL, the default local development setup is optimized for SQLite. Switching to PostgreSQL would require modifying [`packages/db/drizzle.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/db/drizzle.ts) to use the `drizzle-orm/postgres-js` driver and adjusting the `DATABASE_URL` format accordingly, which is not covered by the standard development documentation.

### Where are the database migration files stored?

All migration SQL files are located in the `packages/db/drizzle/` directory (e.g., [[`packages/db/drizzle/0084_rule_engine_multi_list_support.sql`](https://github.com/karakeep-app/karakeep/blob/main/packages/db/drizzle/0084_rule_engine_multi_list_support.sql)](https://github.com/karakeep-app/karakeep/tree/main/packages/db/drizzle)). These files are executed automatically by the `migrate()` function in [[`packages/db/drizzle.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/db/drizzle.ts)](https://github.com/karakeep-app/karakeep/blob/main/packages/db/drizzle.ts) when the application starts.