> Markdown export: /developers/getting-started.md
> HTML: /developers/getting-started
---
description: Self-hosted deployment quick start — Docker Compose, environment variables, and production hardening for Eigen Mesh operators.
audience: operator
---

# Eigen Mesh — Overview & quick start

> **In plain terms:** This page is for operators who want to run Eigen Mesh on their own server with Docker. If you are new to Eigen Mesh, start with [What is Eigen Mesh?](/developers/what-is-eigenmesh). If Eigen operates your instance, see [Onboarding (managed)](/developers/onboarding-managed).

## Who this is for

| Audience | Start here |
|----------|------------|
| **End users (managed hosting)** | [What is Eigen Mesh?](/developers/what-is-eigenmesh) → [Onboarding (managed)](/developers/onboarding-managed) |
| **Operators** (self-hosters) | This page → [Environment variables](/developers/environment-variables) |
| **Integrators** (MCP / API) | [MCP overview](/developers/mcp-overview) → [Connect Cursor or Claude](/developers/cursor-and-claude) |
| **Contributors** (eigen codebase) | [For contributors: architecture map](/developers/contributor-architecture) |

For managed hosting (Eigen operates the stack), see [Onboarding (managed)](/developers/onboarding-managed).

---

## Self-hosting

Eigen Mesh is a self-hostable memory infrastructure app: capture thoughts, enrich them in the background, and retrieve them through hybrid search and **MCP tools** your assistant can call directly.

> **About this documentation site**
>
> You are reading docs published from the **eigenWebsite** repository. Deploy commands, Docker Compose, and database migrations run against the separate **[eigen product repository](https://github.com/your-org/eigen)** — not this marketing/docs repo.

### Stack

| Component | Technology |
|-----------|------------|
| App | SvelteKit with `@sveltejs/adapter-node` on port 3000 |
| Database | PostgreSQL 16 with pgvector and Apache AGE |
| Auth | Better Auth, Drizzle ORM |

### Architecture

| Service | Container | Role |
|---------|-----------|------|
| `app` | `eigen-app` | SvelteKit app on port 3000 |
| `db` | `eigen-db` | PostgreSQL 16 with pgvector + Apache AGE on port 5432 |

Both services are defined in [`docker-compose.yaml`](https://github.com/your-org/eigen/blob/main/docker-compose.yaml) in the eigen repo.

### Prerequisites

- Docker with the `docker compose` plugin (Docker Desktop, OrbStack, or Linux)
- Git

No Node.js or npm is required at deploy time unless you run first-run migrations from the host.

### Quick start

```sh
git clone https://github.com/your-org/eigen.git && cd eigen
cp .env.example .env
# Edit .env — at minimum set BETTER_AUTH_SECRET, TENANT_MASTER_KEY, and LLM gateway vars (see Environment variables)
docker compose up -d --build
```

On **first deploy**, initialize the database schema:

```sh
npm install
npm run db:push:force
npm run db:rls
```

The app is available at `http://<your-host>:3000`.

> **Pro tip:** For automated first-run setup, add an init step that runs `node node_modules/drizzle-kit/bin.cjs push --force && node scripts/apply-rls.mjs` before the app server starts. See [Production hardening](#production-hardening) below.

### Required environment variables

See the canonical [Environment variables](/developers/environment-variables) reference for the full table. At minimum before going live:

| Variable | Purpose |
|----------|---------|
| `BETTER_AUTH_SECRET` | Session encryption — `openssl rand -base64 32` |
| `TENANT_MASTER_KEY` | Per-tenant envelope encryption |
| `AGE_GRAPH_NAME` | Apache AGE graph name (default `eigen_graph`) |
| `ORIGIN` | Public URL users and OAuth callbacks use |
| `LLM_BASE_URL`, `LLM_API_KEY`, `LLM_RULE_CHAT`, `LLM_RULE_EMBEDDING` | LLM gateway for chat and embeddings |

### Deploying to Coolify

1. Connect the **[eigen repository](https://github.com/your-org/eigen)** in Coolify.
2. Select **Docker Compose** as the build pack (Coolify detects `compose.yaml`).
3. Add environment variables from [Environment variables](/developers/environment-variables).
4. Deploy and wait for both containers to start.
5. **First-run migration** — use Coolify's **Execute Command** on the `eigen-app` container:
   ```sh
   npx drizzle-kit push --force && node scripts/apply-rls.mjs
   ```

#### Why Docker Compose?

The app requires PostgreSQL with pgvector and AGE. The standalone Dockerfile only builds the app image. **Docker Compose is the correct build pack.**

#### Port mapping

Default mappings in compose: `3000:3000` (app), `5432:5432` (Postgres). Change in `docker-compose.yaml` if they conflict on your host.

### First-run setup

The compose stack does **not** auto-apply migrations on every startup. After the first `docker compose up`:

```sh
# From a machine with network access to the DB:
DATABASE_URL="postgres://eigen:eigen@<your-host>:5432/eigen" npx drizzle-kit push --force
DATABASE_URL="postgres://eigen:eigen@<your-host>:5432/eigen" node scripts/apply-rls.mjs
```

Or from inside the app container:

```sh
docker compose exec app npx drizzle-kit push --force
docker compose exec app node scripts/apply-rls.mjs
```

### Production hardening

Before going live:

1. Change all default secrets (`BETTER_AUTH_SECRET`, `TENANT_MASTER_KEY`, DB passwords).
2. Set `ORIGIN` to your actual domain.
3. **Restrict Postgres port** — remove `5432:5432` from compose so the database is internal-only.
4. Use a real LLM gateway with OpenAI-compatible `/api/v1/chat/completions` and `/api/v1/embeddings`.
5. Add an app healthcheck in `compose.yaml`:

```yaml
app:
  healthcheck:
    test: ["CMD", "node", "-e", "fetch('http://localhost:3000/api/health').then(r => process.exit(r.ok?0:1))"]
    interval: 30s
    retries: 3
```

6. Pin the Node.js image patch if needed (`node:22-bookworm-slim` in the eigen Dockerfile).

### Development (local, non-containerized)

Run these commands in the **[eigen repository](https://github.com/your-org/eigen)**:

```sh
npm install
cp .env.example .env
npm run db:up      # start Postgres container only
npm run dev        # SvelteKit dev server on :5173
```

### Database lifecycle commands

All commands below are run from the **eigen** repo:

| Command | What it does |
|---------|-------------|
| `npm run db:up` | Start `db` container only |
| `npm run db:down` | Stop all compose services |
| `npm run db:reset` | Stop services and delete DB volume (destructive) |
| `npm run db:push` | Apply Drizzle schema (interactive) |
| `npm run db:push:force` | Apply Drizzle schema (non-interactive) |
| `npm run db:rls` | Apply Row-Level Security policies |
| `npm run db:init` | `db:push:force` + `db:rls` |
| `npm run stack:up` | Build and start all containers |
| `npm run stack:down` | Stop all containers |

## Troubleshooting

See [Troubleshooting](/developers/troubleshooting) for deployment, LLM, and MCP issues.

## Next steps

- [Onboarding (managed)](/developers/onboarding-managed) — managed users
- [Self-hosted setup](/developers/self-hosted-setup) — operator provisioning
- [MCP overview](/developers/mcp-overview) — connect your assistant
- [How memory works](/developers/how-memory-works) — capture, retrieval, consolidation

## License

Apache-2.0. See [LICENSE](https://github.com/your-org/eigen/blob/main/LICENSE) in the eigen repository.
