# How Configuration is Handled in the TREK Server: Environment Variables, File Persistence, and Runtime Constants

> Discover how TREK server manages configuration using environment variables, file persistence, and runtime constants for efficient application setup and operation.

- Repository: [Maurice/TREK](https://github.com/mauriceboe/TREK)
- Tags: internals
- Published: 2026-06-27

---

**The TREK server manages configuration through a hybrid system that prioritizes environment variables, falls back to persisted files in the `data/` directory, and exposes derived constants throughout the application, with a minimal public endpoint for client bootstrapping.**

The TREK server's configuration system is centralized in [`server/src/config.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/config.ts) and implements a resilient multi-layer approach. It combines **environment variables**, **file-based secret persistence**, and **runtime-derived constants** to ensure sensitive keys survive restarts while allowing flexible deployment overrides. This architecture supports everything from encryption keys to session durations, with a type-safe public API for initial client configuration.

## Configuration Loading Hierarchy in [`server/src/config.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/config.ts)

The core configuration logic resides in [`server/src/config.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/config.ts), which implements a three-tier resolution strategy.

### Environment Variable Resolution

The server first checks `process.env` for critical secrets and settings. Variables like `ENCRYPTION_KEY`, `JWT_SECRET`, `DEFAULT_LANGUAGE`, and `SESSION_DURATION` are read directly from the environment. This allows Docker deployments and cloud platforms to inject configuration without modifying source code.

### File-Based Persistence in the `data/` Directory

When environment variables are missing, the system falls back to files stored in the `data/` directory. For example, if `ENCRYPTION_KEY` is unset, the code checks for `data/.encryption_key`. If `JWT_SECRET` is missing, the server reads from `data/.jwt_secret` or generates a fresh secret using `crypto.randomBytes(32).toString('hex')`. Critically, these resolved values are written back to their respective files upon startup, ensuring subsequent restarts maintain consistent secrets without requiring persistent environment variables.

### Derived Application Constants

After raw values are resolved, the module exports convenience constants used throughout the codebase. The `DEFAULT_LANGUAGE` constant validates `process.env.DEFAULT_LANGUAGE` against `SUPPORTED_LANG_CODES`, defaulting to `'en'`. Session durations are parsed from human-readable strings like `"30d"` or `"1h"` into milliseconds (`SESSION_DURATION_MS`) and seconds for JWT expiration. These derived values are imported by services such as [`server/src/services/authService.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/services/authService.ts) for token signing operations.

## Public Configuration Endpoint

The TREK server exposes a minimal public API for pre-login client configuration.

### NestJS ConfigModule Implementation

A dedicated NestJS module in [`server/src/nest/config/config.module.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/nest/config/config.module.ts) registers the `ConfigController`. This controller exposes a single GET endpoint at `/api/config` that returns only the `DEFAULT_LANGUAGE` value. This allows the client to localize the login page before authentication occurs.

### Zod Schema Validation

The response shape is enforced using Zod in [`shared/src/config/config.schema.ts`](https://github.com/mauriceboe/TREK/blob/main/shared/src/config/config.schema.ts). The `publicConfigSchema` validates that the endpoint returns an object with a `defaultLanguage` string property, ensuring type safety across the client-server boundary.

## Configuration Usage Examples

### Accessing Secrets in Authentication Services

Services import constants directly from the configuration module:

```typescript
import { JWT_SECRET, SESSION_DURATION_SECONDS } from '../../config';
import jwt from 'jsonwebtoken';

// Sign a token using the resolved secret
const token = jwt.sign({ userId }, JWT_SECRET, { 
  expiresIn: SESSION_DURATION_SECONDS 
});

```

This pattern appears in [`server/src/services/authService.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/services/authService.ts) where JWT signing operations rely on the persisted secrets.

### Overriding Configuration with Docker Compose

Deployers can override secrets via environment variables in [`docker-compose.yml`](https://github.com/mauriceboe/TREK/blob/main/docker-compose.yml):

```yaml
services:
  trek-server:
    environment:
      - ENCRYPTION_KEY=super-secret-key-123
      - JWT_SECRET=my-jwt-secret
      - DEFAULT_LANGUAGE=de
      - SESSION_DURATION=7d

```

The server will persist these values to the `data/` directory on first boot.

### Fetching Public Config from the Client

The client retrieves localization settings before login:

```typescript
// client/src/api.ts
export async function fetchPublicConfig() {
  const res = await fetch('/api/config');
  const { defaultLanguage } = await res.json();
  return defaultLanguage;
}

```

## Key Configuration Files

| File | Responsibility |
|------|----------------|
| [`server/src/config.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/config.ts) | Central loader, env-var resolution, secret persistence, constant derivation |
| [`server/src/nest/config/config.module.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/nest/config/config.module.ts) | NestJS module registration for the public endpoint |
| [`server/src/nest/config/config.controller.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/nest/config/config.controller.ts) | `/api/config` controller exposing `DEFAULT_LANGUAGE` |
| [`shared/src/config/config.schema.ts`](https://github.com/mauriceboe/TREK/blob/main/shared/src/config/config.schema.ts) | Zod schema for public configuration validation |
| [`server/src/services/authService.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/services/authService.ts) | Consumer of `JWT_SECRET` and session constants |
| [`docker-compose.yml`](https://github.com/mauriceboe/TREK/blob/main/docker-compose.yml) | Example environment variable injection |

## Summary

- **Environment variables** take precedence for all configuration values in the TREK server.
- **File persistence** in `data/` ensures secret consistency across restarts when env vars are absent.
- **Derived constants** like `SESSION_DURATION_MS` and `DEFAULT_LANGUAGE` provide type-safe, validated values used throughout the application.
- **Public endpoint** `/api/config` exposes only the default language via a NestJS controller validated by Zod schemas.
- **Zero-downtime rotation** is supported by updating env vars and restarting, with automatic persistence to the data directory.

## Frequently Asked Questions

### Where does TREK store generated secrets when environment variables are missing?

When `ENCRYPTION_KEY` or `JWT_SECRET` are not provided via `process.env`, the server reads from or writes to the `data/` directory. Specifically, it checks `data/.encryption_key` and `data/.jwt_secret`. If these files do not exist, the server generates cryptographically secure random values and persists them to these files for subsequent restarts.

### How is the session duration configured in TREK?

The session duration is controlled via the `SESSION_DURATION` environment variable using human-readable strings like `"30d"`, `"1h"`, or `"24h"`. The [`server/src/config.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/config.ts) module parses these strings into milliseconds (`SESSION_DURATION_MS`) and seconds using a duration parser, defaulting to 24 hours if unspecified.

### What configuration data is exposed to unauthenticated clients?

The public `/api/config` endpoint exposes only the `DEFAULT_LANGUAGE` setting. This minimal exposure reduces the attack surface while allowing the client application to render localized login pages before a user authenticates. The response shape is validated against the Zod schema defined in [`shared/src/config/config.schema.ts`](https://github.com/mauriceboe/TREK/blob/main/shared/src/config/config.schema.ts).

### How do services access configuration constants in the TREK server?

Services import constants directly from [`server/src/config.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/config.ts). For example, the authentication service imports `JWT_SECRET` and `SESSION_DURATION_SECONDS` to sign tokens. This direct import pattern avoids global state and provides compile-time checking for configuration values.