Skip to content
Build a serviceDocs 1.3.x

Environment Configuration ​

Connectum provides environment validation using Zod schemas. parseEnvConfig() returns configuration values; wire them explicitly into the server and modules. PORT and LISTEN are also read directly when the corresponding server options are omitted. The remaining schema fields do not configure modules merely by being present in the environment.

ConnectumEnvSchema ​

The ConnectumEnvSchema exported from @connectum/core defines all recognized environment variables:

typescript
import { parseEnvConfig } from '@connectum/core';

const config = parseEnvConfig();

console.log(config.PORT);           // 5000 (default)
console.log(config.LISTEN);         // "0.0.0.0" (default)
console.log(config.LOG_LEVEL);      // "info" (default)
console.log(config.NODE_ENV);       // "development" (default)

Environment Variables Reference ​

Server ​

VariableTypeDefaultDescription
PORTnumber5000Server port, a whole number from 1 to 65535 written in decimal digits. A fractional value such as 80.5, or a notation Number() would read (0x50, 1e3, +80, spaces around the digits), is rejected with an error on PORT; leading zeros stay decimal (08080 is 8080)
LISTENstring"0.0.0.0"Listen address
NODE_ENVenum"development""development", "production", or "test"

Logging ​

VariableTypeDefaultDescription
LOG_LEVELenum"info""debug", "info", "warn", or "error"
LOG_FORMATenum"json""json" (structured) or "pretty" (human-readable)
LOG_BACKENDenum"otel""otel", "pino", or "console"

Health Check ​

VariableTypeDefaultDescription
HTTP_HEALTH_ENABLEDbooleanfalseEnable HTTP health endpoints (/healthz, /health, /readyz)
HTTP_HEALTH_PATHstring"/healthz"Primary HTTP health endpoint path

OpenTelemetry ​

VariableTypeDefaultDescription
OTEL_SERVICE_NAMEstring--Service name reported to the collector. An empty value is read as unset, as the OpenTelemetry SDK reads its own variables
OTEL_EXPORTER_OTLP_ENDPOINTstring (url)--OTLP collector endpoint, an absolute http: or https: URL (e.g. http://localhost:4318); localhost:4318 and ftp://collector are rejected with an error on the variable; an empty value is read as unset

Graceful Shutdown ​

VariableTypeDefaultDescription
GRACEFUL_SHUTDOWN_ENABLEDbooleantrueEnable automatic graceful shutdown on SIGTERM/SIGINT
GRACEFUL_SHUTDOWN_TIMEOUT_MSnumber30000Maximum time (ms) to wait for in-flight requests: a whole number from 0 to 300000

An empty or whitespace-only GRACEFUL_SHUTDOWN_TIMEOUT_MS and a fractional value such as 1.5 are rejected with an issue on the variable, the way an empty PORT is. Leave the variable out to get the default. 0 is accepted and means "do not wait for in-flight requests" (see Graceful Shutdown).

TIP

Boolean environment variables accept "true", "false", "1", "0", "yes", and "no".

Parsing and Validation ​

parseEnvConfig() ​

Parses process.env (or a custom object) and throws a ZodError if validation fails:

typescript
import { parseEnvConfig } from '@connectum/core';

try {
  const config = parseEnvConfig();
  console.log(`Starting on port ${config.PORT}`);
} catch (err) {
  console.error('Invalid configuration:', err instanceof Error ? err.message : err);
  process.exit(1);
}

safeParseEnvConfig() ​

Returns a Zod result object instead of throwing:

typescript
import { safeParseEnvConfig } from '@connectum/core';

const result = safeParseEnvConfig();

if (result.success) {
  console.log(`Port: ${result.data.PORT}`);
} else {
  console.error('Validation errors:');
  console.error(result.error.format());
  process.exit(1);
}

Custom Environment Source ​

Both functions accept an optional env object, useful for testing:

typescript
const config = parseEnvConfig({
  PORT: '8080',
  NODE_ENV: 'production',
  LOG_LEVEL: 'warn',
});

Using Config with createServer() ​

Wire the parsed values explicitly. The schema enables graceful shutdown by default, while createServer() leaves autoShutdown disabled unless you set it:

typescript
import { createServer, parseEnvConfig } from '@connectum/core';
import { Healthcheck, healthcheckManager, ServingStatus } from '@connectum/healthcheck';
import { Reflection } from '@connectum/reflection';
import { greeterService } from './services/greeterService.ts';

const env = parseEnvConfig();

const server = createServer({
  services: [greeterService],
  port: env.PORT,
  host: env.LISTEN,
  protocols: [
    Healthcheck({
      httpEnabled: env.HTTP_HEALTH_ENABLED,
      httpPaths: [env.HTTP_HEALTH_PATH, '/health', '/readyz'],
    }),
    Reflection(),
  ],
  shutdown: {
    autoShutdown: env.GRACEFUL_SHUTDOWN_ENABLED,
    timeout: env.GRACEFUL_SHUTDOWN_TIMEOUT_MS,
  },
});

server.on('ready', () => {
  healthcheckManager.update(ServingStatus.SERVING);
});

await server.start();

Options passed to createServer() directly get the same fail-fast check as the variables. port must be an integer from 0 (a free port chosen by the system) to 65535, and host a non-empty string; any other value, a numeric string such as "5000" included, throws a TypeError or RangeError that names the option. Before this check, a non-numeric string port was read as a Unix socket path and an empty host bound every interface.

Server log messages ​

The LOG_* variables above belong to the schema; createServer() does not read them to choose where its own messages go (the listening address, received signals, shutdown problems, transport warnings). Those go to console unless you pass a logger object with info, warn and error functions. See Server log messages for the full list and the rules of the option.

TLS Configuration ​

TLS is configured via the tls option in createServer(). Certificates can be loaded from explicit paths or a directory:

typescript
import { createServer } from '@connectum/core';

// Option A: Explicit paths
const serverWithPaths = createServer({
  services: [routes],
  tls: {
    keyPath: '/etc/ssl/server.key',
    certPath: '/etc/ssl/server.crt',
  },
});

// Option B: Directory (looks for server.key and server.crt)
const serverWithDirectory = createServer({
  services: [routes],
  tls: {
    dirPath: '/etc/ssl/certs',
  },
});

The TLS_DIR_PATH environment variable sets the default directory for getTLSPath():

VariableDefault (dev)Default (prod)
TLS_DIR_PATH../../../keys (relative to cwd)cwd

WARNING

In production, always set TLS_DIR_PATH explicitly or provide keyPath/certPath in the tls option. Provide keyPath and certPath together: setting only one is rejected with an error naming the missing one.

Extending the Schema ​

You can compose ConnectumEnvSchema with your own application-specific variables using Zod's .merge() or .extend():

typescript
import { z } from 'zod';
import { ConnectumEnvSchema } from '@connectum/core';

const AppEnvSchema = ConnectumEnvSchema.extend({
  DATABASE_URL: z.string().url(),
  REDIS_URL: z.string().url().optional(),
  API_KEY: z.string().min(32),
});

type AppEnv = z.infer<typeof AppEnvSchema>;

const config: AppEnv = AppEnvSchema.parse(process.env);

Configuration by Environment ​

These files show values to supply through your process environment. Load a local file explicitly (for example node --env-file=.env src/index.ts); parseEnvConfig() does not read .env files. Logging and OpenTelemetry still need their module configuration; see Observability.

Development .env ​

bash
PORT=5000
NODE_ENV=development
LOG_LEVEL=debug
LOG_FORMAT=pretty
LOG_BACKEND=console
HTTP_HEALTH_ENABLED=true
GRACEFUL_SHUTDOWN_ENABLED=false

Production .env ​

bash
PORT=5000
NODE_ENV=production
LOG_LEVEL=warn
LOG_FORMAT=json
LOG_BACKEND=otel
OTEL_SERVICE_NAME=my-service
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
HTTP_HEALTH_ENABLED=true
GRACEFUL_SHUTDOWN_ENABLED=true
GRACEFUL_SHUTDOWN_TIMEOUT_MS=30000
TLS_DIR_PATH=/etc/ssl/connectum

Docker and Kubernetes ​

Dockerfile ​

Use the Docker guide for dependency installation, generated contracts, and runtime image selection. Supply the environment values above when starting the container.

Kubernetes Pod Spec (excerpt) ​

yaml
containers:
  - name: my-service
    image: my-service:latest
    ports:
      - containerPort: 5000
    env:
      - { name: NODE_ENV, value: "production" }
      - { name: LOG_LEVEL, value: "info" }
      - { name: OTEL_SERVICE_NAME, value: "my-service" }
      - { name: HTTP_HEALTH_ENABLED, value: "true" }
      - { name: GRACEFUL_SHUTDOWN_ENABLED, value: "true" }
    livenessProbe:
      httpGet: { path: /healthz, port: 5000 }
    readinessProbe:
      httpGet: { path: /readyz, port: 5000 }

TIP

Budget terminationGracePeriodSeconds for the pre-stop delay, connection drain, bounded shutdown hooks, and a margin. A lower connection-drain timeout alone does not ensure cleanup finishes; see Graceful shutdown.