# How @n8n/config Manages Centralized Configuration in n8n: Decorators, Zod, and Dependency Injection

> Learn how @n8n/config centralizes n8n configuration with TypeScript decorators, Zod validation, and dependency injection for type-safe runtime settings.

- Repository: [n8n - Workflow Automation/n8n](https://github.com/n8n-io/n8n)
- Tags: internals
- Published: 2026-02-24

---

**@n8n/config provides a centralized, type-safe configuration system for n8n using TypeScript decorators, Zod validation schemas, and dependency injection to aggregate all runtime settings into a single hierarchical GlobalConfig object.**

The n8n workflow automation platform manages dozens of runtime settings—from database URLs to AI service endpoints—through a dedicated centralized configuration package. The `@n8n/config` package serves as the single source of truth for every environment variable, eliminating scattered `process.env` access throughout the codebase. By combining decorator-based metadata, runtime validation, and dependency injection, the system ensures that configuration is validated at startup and accessible via strongly-typed objects anywhere in the application.

## The Architecture of Centralized Configuration

The `@n8n/config` system is built on three architectural pillars that work together to provide type safety and centralized management.

### TypeScript Decorators as the Foundation

Configuration containers are defined using TypeScript classes decorated with `@Config`, `@Env`, and `@Nested`. These decorators attach metadata that a factory function reads during dependency resolution. In [`src/decorators.ts`](https://github.com/n8n-io/n8n/blob/main/src/decorators.ts), the `@Config` decorator registers a factory with the `@n8n/di` container that walks a metadata map, reads environment variables, applies Zod schemas, and injects nested config objects.

### Zod Schema Validation

Runtime type safety is enforced through Zod schemas passed to the `@Env` decorator. When the factory resolves a configuration value, it executes `schema.safeParse(value)` against the raw environment variable. If validation fails, the system falls back to the property's default value and emits a warning. This pattern is used for strict enums like `protocolSchema = z.enum(['http', 'https'])` in the top-level configuration.

### Dependency Injection Integration

All configuration classes are registered as services within the `@n8n/di` container. The `@Config` decorator wraps the class with `Service({ factory })`, making the fully-populated configuration available via `Container.get(GlobalConfig)` or through constructor injection in other services.

## Core Decorators for Configuration Management

The package exposes three primary decorators that define how environment variables map to typed properties.

### @Config – The Class-Level Decorator

Applied to any class that should serve as a configuration container, the `@Config` decorator in [`src/decorators.ts`](https://github.com/n8n-io/n8n/blob/main/src/decorators.ts) (lines 37-99) registers the class with the DI container and attaches a factory function. This factory is responsible for instantiating the class, reading environment variables based on metadata keys, and recursively resolving nested configurations.

### @Env – Mapping Environment Variables

The `@Env` decorator (lines 109-126 in [`src/decorators.ts`](https://github.com/n8n-io/n8n/blob/main/src/decorators.ts)) associates a class property with a specific environment variable name. It accepts an optional Zod schema for validation. During resolution, the system checks for the environment variable; if not found, it checks for a `<VAR>_FILE` variant for file-based secrets, then parses and validates the value before assignment.

### @Nested – Building Hierarchical Configs

For complex configuration trees, the `@Nested` decorator (lines 101-107) declares that a property is itself a configuration class. The factory fetches this nested class from the DI container during parent resolution, enabling deep hierarchies such as `config.database.url` or `config.ai.enabled` without manual instantiation.

## How GlobalConfig Aggregates All Configuration

The `GlobalConfig` class in [`src/index.ts`](https://github.com/n8n-io/n8n/blob/main/src/index.ts) (lines 69-132) serves as the root configuration object that aggregates every individual configuration section. It imports and nests specialized configs like `AuthConfig`, `DatabaseConfig`, `AiConfig`, and others from the `configs/` directory.

Each nested configuration is decorated with `@Nested`, while primitive values use `@Env` with appropriate Zod schemas. For example, the protocol field uses `protocolSchema = z.enum(['http', 'https'])` to ensure only valid HTTP protocols are accepted. The [`src/index.ts`](https://github.com/n8n-io/n8n/blob/main/src/index.ts) file also re-exports all individual config classes and helper types, providing a single entry point: `import { GlobalConfig } from '@n8n/config'`.

## Accessing Configuration in Your Code

Once the configuration system is initialized, you can access the centralized config through the dependency injection container.

### Via Container Resolution

For one-off access or in non-service contexts, resolve the configuration directly from the DI container:

```typescript
import { Container } from '@n8n/di';
import { GlobalConfig } from '@n8n/config';

// Resolve once – the DI container builds the whole hierarchy
const config = Container.get(GlobalConfig);

// Access nested properties
console.log('Server port:', config.port);              // from N8N_PORT
console.log('Database URL:', config.database.url);     // from DATABASE_URL (or file)
console.log('AI enabled?', config.ai.enabled);         // from N8N_AI_ENABLED

```

### Via Constructor Injection

In service classes, inject the configuration through the constructor for cleaner testing and dependency management:

```typescript
import { Service } from '@n8n/di';
import { GlobalConfig } from '@n8n/config';

@Service()
export class WorkflowService {
  constructor(private readonly config: GlobalConfig) {}

  isFeatureEnabled(): boolean {
    return this.config.ai.enabled && this.config.auth.jwtSecret !== '';
  }
}

```

Because `GlobalConfig` is registered as a DI service, the container automatically provides the fully-populated instance with all environment variables resolved, validated, and nested configs injected.

## Advanced Features: File-Based Secrets and Validation

The configuration system supports enterprise deployment patterns through file-based secrets and strict runtime validation.

**File-Based Secrets**: For sensitive values like TLS certificates or database passwords, the system checks for `<VAR>_FILE` environment variables before falling back to the direct variable. In [`src/decorators.ts`](https://github.com/n8n-io/n8n/blob/main/src/decorators.ts) (lines 19-34), the `readEnv` function loads file contents and trims whitespace, enabling Docker secrets or Kubernetes mounted volumes to inject configuration securely.

**Zod Validation**: When defining configuration properties, you can pass a Zod schema to the `@Env` decorator. The factory executes `schema.safeParse(value)` during resolution. If validation fails, the property falls back to its default value and the system emits a warning. This ensures that malformed environment variables cannot crash the application or inject invalid state.

## Summary

- **@n8n/config** serves as the single source of truth for all n8n runtime settings, eliminating scattered `process.env` access.
- The system uses **TypeScript decorators** (`@Config`, `@Env`, `@Nested`) to define typed configuration classes with metadata-driven resolution.
- **Zod schemas** provide runtime validation, falling back to defaults when environment variables are malformed.
- **File-based secrets** (`<VAR>_FILE`) enable secure injection of sensitive values via Docker or Kubernetes.
- **Dependency injection** via `@n8n/di` makes the `GlobalConfig` available through `Container.get()` or constructor injection anywhere in the codebase.

## Frequently Asked Questions

### What is the primary purpose of @n8n/config?

The primary purpose of `@n8n/config` is to provide a centralized, type-safe configuration management system for the n8n workflow automation platform. It aggregates all runtime environment variables into a single hierarchical `GlobalConfig` object, ensuring that settings are validated at startup and accessible via dependency injection throughout the application without direct `process.env` references.

### How does @n8n/config handle environment variable validation?

Environment variable validation is handled through **Zod schemas** passed to the `@Env` decorator. When the configuration factory resolves a property, it executes `schema.safeParse(value)` against the raw environment variable. If validation fails, the system falls back to the property's default value and emits a warning, preventing invalid configuration from crashing the application or causing undefined behavior.

### Can I use file-based secrets instead of environment variables?

Yes, the configuration system supports file-based secrets through the `<VAR>_FILE` pattern. If an environment variable is not set directly but a corresponding `<VAR>_FILE` variable points to a file path, the system loads the file's contents (trimming whitespace) and uses that as the configuration value. This pattern is commonly used for Docker secrets or Kubernetes-mounted volumes to securely inject sensitive data like TLS certificates or database passwords.

### How do I access the configuration in a service class?

You can access the configuration in a service class through **constructor injection** provided by `@n8n/di`. Import `GlobalConfig` from `@n8n/config` and include it in your service's constructor parameters. Because `GlobalConfig` is registered as a DI service via the `@Config` decorator, the container automatically injects the fully-populated configuration instance when resolving your service. Alternatively, you can use `Container.get(GlobalConfig)` for one-off access outside of service constructors.