# How to Configure Kaneo Environment Variables: Production Setup Guide

> Master Kaneo environment variables for production. Learn to configure essential variables like KANEO_CLIENT_URL, AUTH_SECRET, and DATABASE_URL in your .env file for seamless API and web frontend operation.

- Repository: [kaneo.app/kaneo](https://github.com/usekaneo/kaneo)
- Tags: how-to-guide
- Published: 2026-08-08

---

**Kaneo requires a single `.env` file at the repository root containing core variables like `KANEO_CLIENT_URL`, `AUTH_SECRET`, and `DATABASE_URL`, which the API and web frontend read via `process.env` at startup.**

Kaneo is an open-source project management platform that centralizes configuration through environment variables. To configure Kaneo environment variables for production deployment, you must populate a `.env` file with URLs, secrets, and database connections that both the API server and web application consume during initialization.

## Required Environment Variables

### Core Application URLs

**`KANEO_CLIENT_URL`** defines the public URL of the web application (e.g., `https://kaneo.example.com`). The API uses this to construct absolute links for invitations and webhooks in [`apps/api/src/auth.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/auth.ts) (line 71) and [`apps/api/src/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/index.ts) (line 170).

**`KANEO_API_URL`** specifies the base URL of the API server. The web frontend reads this via **`VITE_API_URL`** at build time, as defined in [`apps/web/vite.config.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/vite.config.ts) (line 12).

### Authentication Security

**`AUTH_SECRET`** requires a minimum 32-character string for JWT signing. The API validates this length on startup in [`apps/api/src/auth.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/auth.ts) (lines 105-107). If the secret is too short or missing, the server aborts immediately with an error message.

### Database Connection

**`DATABASE_URL`** provides the full PostgreSQL connection string (e.g., `postgresql://user:pass@host:5432/db`). Drizzle ORM initializes the connection using this variable in [`apps/api/src/database/prepare-database-startup.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/database/prepare-database-startup.ts) (line 23).

**`POSTGRES_DB`**, **`POSTGRES_USER`**, and **`POSTGRES_PASSWORD`** support migration scripts and testing utilities in [`tests/api-integration/helpers/database.ts`](https://github.com/usekaneo/kaneo/blob/main/tests/api-integration/helpers/database.ts) (lines 9-11).

## Optional Environment Variables

### Redis for WebSocket Broadcasting

Configure **`REDIS_URL`** (e.g., `redis://host:6379`) to enable multi-instance WebSocket broadcasting. If omitted, the system falls back to in-memory broadcasting, which breaks real-time sync across multiple server instances (see [`apps/api/src/ws/broadcast-adapter.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/broadcast-adapter.ts) lines 5-7).

Advanced Redis Sentinel or Cluster configurations use **`REDIS_SENTINELS`**, **`REDIS_CLUSTER_NODES`**, **`REDIS_SENTINEL_MASTER_NAME`**, **`REDIS_SENTINEL_PASSWORD`**, and **`REDIS_SENTINEL_TLS`** as defined in [`apps/api/src/ws/redis-config.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/redis-config.ts).

### S3-Compatible Storage

For image uploads, define these variables consumed in [`apps/api/src/storage/s3.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/storage/s3.ts) (lines 12-23):

- **`S3_ENDPOINT`**: Storage service endpoint
- **`S3_BUCKET`**: Target bucket name
- **`S3_ACCESS_KEY_ID`** and **`S3_SECRET_ACCESS_KEY`**: Credentials
- **`S3_REGION`**: Geographic region
- **`S3_FORCE_PATH_STYLE`**: Set to `true` for MinIO or non-AWS providers
- **`S3_MAX_IMAGE_UPLOAD_BYTES`**: Upload limit (default 5 MiB)
- **`S3_KEY_PREFIX`**: Optional path prefix (e.g., `staging/`)

### OAuth and SSO Providers

Enable third-party authentication with provider-specific variables:

- **GitHub**: `GITHUB_OAUTH_CLIENT_ID`, `GITHUB_OAUTH_CLIENT_SECRET` (used in [`apps/api/src/plugins/github/webhooks/issue-opened.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/plugins/github/webhooks/issue-opened.ts) line 141)
- **Google**: `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET` ([`apps/api/src/auth.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/auth.ts) lines 173-176)
- **Discord**: `DISCORD_CLIENT_ID`, `DISCORD_CLIENT_SECRET` ([`apps/api/src/plugins/discord/events.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/plugins/discord/events.ts) line 109)
- **Custom OAuth**: `CUSTOM_OAUTH_CLIENT_ID`, `CUSTOM_OAUTH_CLIENT_SECRET`, `CUSTOM_OAUTH_AUTHORIZE_URL`, `CUSTOM_OAUTH_TOKEN_URL`, `CUSTOM_OAUTH_USER_INFO_URL` ([`apps/api/src/auth.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/auth.ts) lines 180-190)

### Email and Billing

- **SMTP settings**: `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASSWORD`, `SMTP_FROM` (required for invitation emails in [`apps/api/src/email/send-email.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/email/send-email.ts))
- **Stripe integration**: `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET` (used in [`apps/api/src/billing/stripe.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/billing/stripe.ts) and [`stripe-webhook.ts`](https://github.com/usekaneo/kaneo/blob/main/stripe-webhook.ts))

## Step-by-Step Configuration

1. **Create the `.env` file** at the repository root:

   ```bash
   touch .env
   ```

2. **Add required variables**:

   ```bash
   KANEO_CLIENT_URL=https://your-domain.com
   KANEO_API_URL=https://api.your-domain.com
   AUTH_SECRET=your-minimum-32-character-secret-key-here
   DATABASE_URL=postgresql://user:password@localhost:5432/kaneo
   CORS_ORIGINS=https://your-domain.com
   ```

3. **Add feature-specific variables** based on your infrastructure (Redis, S3, OAuth).

4. **Secure the file** by ensuring `.env` is listed in `.gitignore` to prevent accidental commits of secrets.

5. **Restart services** to apply changes:

   ```bash
   pnpm --filter @kaneo/api dev
   pnpm --filter @kaneo/web dev
   ```

## Code Implementation Examples

Reading variables in the API:

```typescript
// apps/api/src/auth.ts
const clientUrl = process.env.KANEO_CLIENT_URL || "http://localhost:5173";
const secret = process.env.AUTH_SECRET || "";

if (secret.length < 32) {
  throw new Error("AUTH_SECRET is less than 32 characters...");
}

```

Frontend API URL resolution:

```typescript
// apps/web/src/fetchers/project/get-project.ts
const base = import.meta.env.VITE_API_URL ?? process.env.KANEO_API_URL;

export async function getProject(id: string) {
  const res = await fetch(`${base}/api/project/${id}`);
  return res.json();
}

```

Generating invitation links with fallback:

```typescript
// apps/web/src/lib/invitation-link.ts
export function createInvitationLink(token: string) {
  const origin = typeof window !== "undefined" 
    ? window.location.origin 
    : process.env.KANEO_CLIENT_URL;
  return `${origin}/invitation/accept/${token}`;
}

```

## Troubleshooting Common Issues

- **`AUTH_SECRET` too short**: The API aborts startup with "AUTH_SECRET is less than 32 characters" if the secret is under 32 characters ([`apps/api/src/auth.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/auth.ts) lines 105-107).
- **CORS failures**: Missing `KANEO_CLIENT_URL` or misconfigured `CORS_ORIGINS` causes the API to reject cross-origin requests ([`apps/api/src/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/index.ts) line 181).
- **Database connection errors**: Verify `DATABASE_URL` format includes the full protocol (`postgresql://`) as expected by [`apps/api/src/database/prepare-database-startup.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/database/prepare-database-startup.ts) (line 23).
- **S3 upload failures**: For non-AWS providers, ensure `S3_FORCE_PATH_STYLE=true` is set, and verify endpoint credentials in [`apps/api/src/storage/s3.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/storage/s3.ts).

## Summary

- Kaneo uses a single `.env` file at the repository root for all configuration, read by both the API and web frontend.
- **Required variables**: `KANEO_CLIENT_URL`, `KANEO_API_URL`, `AUTH_SECRET` (minimum 32 characters), and `DATABASE_URL`.
- **Optional integrations**: Redis for multi-instance scaling, S3 for file storage, OAuth providers for SSO, and SMTP for transactional email.
- The API validates critical security requirements at startup and aborts if `AUTH_SECRET` is insufficient.
- Frontend build variables use the `VITE_` prefix to be exposed to the Vite build system.

## Frequently Asked Questions

### What happens if I don't set the AUTH_SECRET?

The API server will terminate immediately on startup with an error indicating the secret is missing or too short, as enforced by the validation logic in [`apps/api/src/auth.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/auth.ts) (lines 105-107).

### Can I use environment variables without a .env file?

Yes. Kaneo reads from `process.env`, so Docker secrets, Kubernetes ConfigMaps, or systemd environment files work as long as variables are present when the Node.js process starts. The `.env` file is simply a convenience for local development.

### How do I configure Redis for multiple Kaneo instances?

Set `REDIS_URL` to your Redis server address (e.g., `redis://localhost:6379`). For production clusters with Sentinel, configure `REDIS_SENTINELS` as a comma-separated list and provide `REDIS_SENTINEL_MASTER_NAME` and `REDIS_SENTINEL_PASSWORD` as defined in [`apps/api/src/ws/redis-config.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/ws/redis-config.ts).

### Why are my S3 uploads failing?

Verify that `S3_ENDPOINT`, `S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY`, and `S3_BUCKET` match your provider's configuration. For non-AWS providers like MinIO or Wasabi, set `S3_FORCE_PATH_STYLE=true` as required by the S3 client initialization in [`apps/api/src/storage/s3.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/storage/s3.ts) (line 22).