How Kaneo Handles Environment Variables for Configuration: A Complete Guide to dotenv-mono

Kaneo centralizes runtime configuration by using the dotenv-mono package to load environment-specific .env files, exposing a strongly-typed settings object through apps/api/src/utils/get-settings.ts.

The open-source project management platform Kaneo (available at usekaneo/kaneo) manages secrets and configuration through a systematic approach that separates code from sensitive data. By leveraging the dotenv-mono ecosystem, Kaneo ensures consistent configuration access across its API while maintaining type safety and test isolation.

The Configuration Architecture: dotenv-mono and get-settings.ts

At the heart of Kaneo's configuration system lies the dotenv-mono package, which serves as the single source of truth for all environment variables. The entry point apps/api/src/utils/get-settings.ts imports the config function from dotenv-mono and constructs a validated settings object that downstream modules consume.

This centralized approach means no other file in the codebase directly accesses process.env. Instead, every module imports the typed configuration object, creating a clear boundary between environment parsing and business logic.

Loading Order and Environment-Specific Files

dotenv-mono reads a hierarchy of .env files located at the repository root based on the current NODE_ENV. The package automatically selects the appropriate file (such as .env.development, .env.production, or .env.test) and merges its values with existing process.env entries.

Kaneo leverages this hierarchy to maintain separate configurations for local development, staging, and production without code changes. The loader respects the standard priority: environment-specific files override base .env files, while existing system environment variables take precedence over file contents.

Consuming Configuration Values Across the API

Kaneo consumes environment variables through the exported settings object in four critical subsystems:

Database Connections

In apps/api/src/database/index.ts, Kaneo retrieves PostgreSQL credentials including POSTGRES_URL and POSTGRES_DB from the settings object to establish database connections.

Authentication Secrets

The apps/api/src/auth.ts module imports JWT_SECRET and SESSION_COOKIE_NAME to configure Hono authentication middleware, ensuring session management relies on externally supplied secrets rather than hardcoded values.

GitHub Integration

The GitHub App implementation at apps/api/src/plugins/github/utils/github-app.ts consumes GITHUB_APP_ID, GITHUB_PRIVATE_KEY, and webhook secrets to authenticate with GitHub's API.

S3 Storage Credentials

File storage operations in apps/api/src/storage/s3.ts obtain S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, and bucket configuration through the same centralized settings object.

// apps/api/src/utils/get-settings.ts
import { config } from "dotenv-mono";

export default function getSettings() {
  const env = config();            // Loads .env files based on NODE_ENV
  return {
    // Database
    dbUrl: env.POSTGRES_URL,
    dbName: env.POSTGRES_DB,

    // Auth
    jwtSecret: env.JWT_SECRET,
    sessionCookie: env.SESSION_COOKIE_NAME,

    // GitHub
    ghAppId: env.GITHUB_APP_ID,
    ghPrivateKey: env.GITHUB_PRIVATE_KEY,

    // S3
    s3KeyId: env.S3_ACCESS_KEY_ID,
    s3Secret: env.S3_SECRET_ACCESS_KEY,
    s3Bucket: env.S3_BUCKET,
  };
}
// apps/api/src/auth.ts
import getSettings from "../utils/get-settings";

const { jwtSecret, sessionCookie } = getSettings();

// Use the secrets to configure Hono authentication middleware
// apps/api/src/storage/s3.ts
import getSettings from "../utils/get-settings";

const { s3KeyId, s3Secret, s3Bucket } = getSettings();

// Initialise AWS SDK client with the retrieved credentials

Type Safety and the Settings Object

The get-settings.ts utility transforms raw environment strings into a strongly-typed configuration object. This pattern provides compile-time safety, ensuring that TypeScript catches missing or mistyped configuration keys before runtime. Downstream code imports this object rather than accessing process.env directly, eliminating string-typo errors and enabling IDE autocomplete for configuration values.

Testing Isolation and Mocking

Kaneo's integration test suite at tests/api-integration/setup.ts mocks the dotenv-mono loader to prevent accidental reads of local .env files during test execution. This isolation ensures deterministic, in-memory configuration that prevents test pollution from developer environment variables or production secrets.

Getting Started: The .env.example Template

New contributors find all required variables documented in apps/api/.env.example. This template lists every configuration key with brief descriptions, allowing developers to copy the file to .env (or environment-specific variants) and populate actual secrets without hunting through source code.

Summary

  • Kaneo uses dotenv-mono to load hierarchical .env files based on NODE_ENV, supporting environment-specific configurations.
  • The apps/api/src/utils/get-settings.ts module centralizes all configuration access, returning a strongly-typed settings object.
  • Database, authentication, GitHub, and S3 modules consume this object rather than accessing process.env directly.
  • Type safety prevents runtime configuration errors through compile-time validation.
  • Integration tests mock the configuration loader to ensure deterministic, isolated environments.
  • apps/api/.env.example serves as the definitive reference for required environment variables.

Frequently Asked Questions

What package does Kaneo use to load environment variables?

Kaneo relies on the dotenv-mono package to parse and load environment files. This package handles the complexity of selecting the correct .env file based on the current NODE_ENV and merging values with existing system environment variables.

How does Kaneo handle different environments like development and production?

Kaneo leverages dotenv-mono's automatic file selection to load .env.development, .env.production, or .env.test depending on the NODE_ENV value. This allows the same codebase to run with different configurations by simply changing the environment variable or file presence.

Where should I define environment variables when self-hosting Kaneo?

Create a .env file in the repository root (or environment-specific variants like .env.production) using apps/api/.env.example as your template. The get-settings.ts utility will automatically load these values when the API starts.

How does Kaneo prevent configuration errors in production?

By exporting a typed settings object from apps/api/src/utils/get-settings.ts, Kaneo ensures that all configuration access happens through a single validated interface. TypeScript will fail compilation if required keys are missing or if code attempts to access undefined configuration properties.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →