メインコンテンツまでスキップ

Configuration

Zelt provides a type-safe configuration system using the @Config decorator and inject() helper.

Defining Configuration

Use the @Config decorator to define a configuration class. Each config class must have a static Token property:

import { Config, Env, inject } from '@zeltjs/core';

@Config
export class DatabaseConfig {
  static readonly Token = DatabaseConfig;

  constructor(private env = inject(Env)) {}

  get host() {
    return this.env.getString('DATABASE_HOST', 'localhost');
  }

  get port() {
    return this.env.getNumber('DATABASE_PORT', 5432);
  }

  get connectionString() {
    return `postgres://${this.host}:${this.port}/mydb`;
  }
}

Using Configuration

Inject configuration into services or controllers using inject():

@Injectable()
export class DatabaseService {
  constructor(private config = inject(DatabaseConfig)) {}

  connect() {
    return this.config.connectionString;
  }
}

Registering Configuration

Register config classes when creating the app:

const app = createApp([http({
    controllers: [AppController],
  })], { configs: [DatabaseConfig] });

Overriding Configuration

Override configuration values for testing by extending the config class:

@Config
export class TestDatabaseConfig extends DatabaseConfig {
  override get host() {
    return 'test-db';
  }

  override get port() {
    return 5433;
  }
}

// In test setup
const app = createApp([http({
    controllers: [AppController],
  })], { configs: [TestDatabaseConfig] });

The Token property is inherited from the parent class, so inject(DatabaseConfig) will receive the overridden TestDatabaseConfig instance.

Environment-Based Configuration

inject(Env) reads environment variables from the platform-specific source registered by the adapter. No additional setup is needed for the common case.

Node.js Environment

When using onNode(), ProcessEnvAdaptor is registered automatically, so inject(Env) reads from process.env without any extra config:

@Config
export class DatabaseConfig {
  static readonly Token = DatabaseConfig;

  constructor(private env = inject(Env)) {}

  get host() {
    return this.env.getString('DATABASE_HOST', 'localhost');
  }

  get port() {
    return this.env.getNumber('DATABASE_PORT', 5432);
  }

  get connectionString() {
    return `postgres://${this.host}:${this.port}/mydb`;
  }
}

const app = createApp([http({
    controllers: [AppController],
  })], { configs: [DatabaseConfig] });

Loading .env Files

To load a .env file, import dotenv/config at the entry point of your application before anything else:

import 'dotenv/config';import { onNode } from '@zeltjs/adapter-node';
// ...rest of app setup

inject(Env) will then read the variables populated by dotenv from process.env.

Cloudflare Workers Environment

For Cloudflare Workers, environment configuration is handled automatically by onCloudflareWorkers(). See the Cloudflare Workers Getting Started guide for details.

TypeScript Decorator Configuration

Zelt supports both TC39 standard decorators and legacy TypeScript decorators. The framework automatically detects which mode is being used at runtime.

For new projects, use TC39 standard decorators. No special TypeScript configuration is needed:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext"
  }
}

Legacy Decorators

For compatibility with existing codebases, enable legacy decorators:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "experimentalDecorators": true
  }
}

Detection Behavior

Zelt automatically detects the decorator mode based on the runtime context:

  • TC39 mode: Decorator receives a context object with kind, name, and metadata properties
  • Legacy mode: Decorator receives target, propertyKey, and descriptor arguments

Both modes work identically from an API perspective—you don't need to change your code when switching between them.