# How Kaneo Handles Configuration: Environment Variables and Type-Safe Settings

> Discover how Kaneo centralizes runtime configuration with type-safe getSettings(). Load environment variables, validate security, and get defaults for local dev.

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

---

**Kaneo centralizes all runtime configuration in a type-safe `getSettings()` helper that loads environment variables via dotenv-mono, validates critical security settings, and supplies sensible defaults for local development.**

Kaneo keeps sensitive credentials out of source control by relying entirely on environment-based configuration. At startup, the application loads a root `.env` file and exposes typed settings through a centralized utility, ensuring every service—from the PostgreSQL database to S3-compatible storage—accesses validated configuration through a single source of truth.

## Centralized Configuration Architecture

### Loading Environment Variables with dotenv-mono

Instead of scattering `process.env` access throughout the codebase, Kaneo uses the **dotenv-mono** package to parse a single `.env` file located at the repository root. This executes before application logic, making all environment variables available through `process.env` to every module in the monorepo.

### The getSettings() Type-Safe Helper

The configuration system's core resides in [`apps/api/src/utils/get-settings.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/utils/get-settings.ts). This module exports a `getSettings()` function that extracts required variables, casts them to appropriate TypeScript types, and provides fallback values—such as defaulting `KANEO_API_URL` to `http://localhost:1337` when undefined.

```typescript
import { getSettings } from "@/utils/get-settings";

const { DATABASE_URL, AUTH_SECRET } = getSettings();

export const db = drizzle(DATABASE_URL, { schema });
export const jwt = new JwtService(AUTH_SECRET);

```

*Source: [`apps/api/src/database/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/database/index.ts) and [`apps/api/src/auth.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/auth.ts)*

## Database and Infrastructure Configuration

### PostgreSQL and Drizzle ORM Setup

In [`apps/api/src/database/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/database/index.ts), the application reads `DATABASE_URL`, `POSTGRES_DB`, `POSTGRES_USER`, and `POSTGRES_PASSWORD` to initialize the Drizzle ORM connection. The settings helper ensures these values are present before attempting to connect, preventing runtime undefined errors.

### Authentication and Session Storage

The authentication layer in [`apps/api/src/auth.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/auth.ts) retrieves `AUTH_SECRET` for JWT signing and `REDIS_URL` for session storage. The system enforces security by validating that `AUTH_SECRET` contains at least 32 characters, throwing a clear error and exiting if this requirement is not met.

```typescript
import { getSettings } from "@/utils/get-settings";

const {
  S3_ENDPOINT,
  S3_BUCKET,
  S3_ACCESS_KEY_ID,
  S3_SECRET_ACCESS_KEY,
  S3_REGION,
  S3_FORCE_PATH_STYLE,
} = getSettings();

export const s3 = new S3Client({
  endpoint: S3_ENDPOINT,
  region: S3_REGION,
  credentials: {
    accessKeyId: S3_ACCESS_KEY_ID,
    secretAccessKey: S3_SECRET_ACCESS_KEY,
  },
  forcePathStyle: S3_FORCE_PATH_STYLE === "true",
});

```

*Source: [`apps/api/src/storage/s3.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/storage/s3.ts)*

## Third-Party Service Integration

### S3-Compatible Object Storage

File attachments are handled by an S3-compatible client configured in [`apps/api/src/storage/s3.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/storage/s3.ts). This module consumes six environment variables: `S3_ENDPOINT`, `S3_BUCKET`, `S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY`, `S3_REGION`, and the optional boolean string `S3_FORCE_PATH_STYLE`.

### GitHub OAuth and App Integration

For GitHub Single Sign-On, [`apps/api/src/plugins/github/utils/github-app.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/plugins/github/utils/github-app.ts) reads `GITHUB_OAUTH_CLIENT_ID`, `GITHUB_OAUTH_CLIENT_SECRET`, `GITHUB_CLIENT_ID`, and `GITHUB_CLIENT_SECRET`. These credentials remain isolated within the plugin utility and are never hard-coded into the source.

## Frontend API Configuration

The web client in [`apps/web/src/lib/utils.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/lib/utils.ts) consumes `VITE_API_URL` (derived from `KANEO_API_URL`) to construct API request URLs. During development, this defaults to `http://localhost:1337`, allowing the frontend to proxy requests to the local API server without manual configuration.

```typescript
import { getSettings } from "@/utils/get-settings";

export const API_URL = getSettings().KANEO_API_URL;

// Usage in a fetcher
export async function getTask(id: string) {
  const res = await fetch(`${API_URL}/tasks/${id}`);
  return res.json();
}

```

*Source: [`apps/web/src/lib/utils.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/lib/utils.ts)*

## Validation and Security Defaults

Kaneo's configuration system enforces security at startup. **Required variables** like `AUTH_SECRET` trigger immediate application shutdown if missing or insufficiently long, while **optional variables** receive sensible defaults. This design prevents the server from starting in a misconfigured state where secrets might be vulnerable or database connections would fail silently.

## Summary

- **dotenv-mono** loads a root `.env` file into `process.env` before application startup
- The **`getSettings()`** helper in [`apps/api/src/utils/get-settings.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/utils/get-settings.ts) provides type-safe access with automatic defaults for local development
- Database connections in [`apps/api/src/database/index.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/database/index.ts) and authentication in [`apps/api/src/auth.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/auth.ts) import configuration through the centralized helper
- S3 storage credentials and GitHub OAuth secrets are isolated in their respective plugin utilities
- The frontend reads `VITE_API_URL` via [`apps/web/src/lib/utils.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/lib/utils.ts) to communicate with the backend API
- Critical security variables undergo length and presence validation to prevent misconfigured deployments

## Frequently Asked Questions

### What environment variables are required to run Kaneo?

At minimum, you must provide `DATABASE_URL` (or individual PostgreSQL credentials `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`), `AUTH_SECRET` (minimum 32 characters), and `REDIS_URL`. For file upload functionality, S3 configuration including `S3_ENDPOINT`, `S3_BUCKET`, and access keys is required.

### How does Kaneo validate configuration at startup?

The `getSettings()` function validates that `AUTH_SECRET` meets minimum length requirements and checks for the presence of mandatory database credentials. If validation fails, the application throws a descriptive error and exits immediately before initializing external connections.

### Can I use a different storage provider than AWS S3?

The current implementation in [`apps/api/src/storage/s3.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/storage/s3.ts) targets S3-compatible APIs. While the configuration system itself is provider-agnostic, switching to a different storage architecture (such as local filesystem or Azure Blob) would require implementing a custom adapter that follows the same pattern of consuming settings via `getSettings()`.

### How do I configure Kaneo for production deployment?

Create a `.env` file at the repository root with production values for `DATABASE_URL`, `AUTH_SECRET`, `REDIS_URL`, and your S3 credentials. Set `KANEO_API_URL` to your public API endpoint (e.g., `https://api.kaneo.example.com`), and ensure `VITE_API_URL` is set accordingly before building the frontend.