Configuration

Manage environment variables with validated, type-safe configuration.

MiiaJS provides a ConfigModule for loading and validating environment variables with any ZodLike schema.

Setup

import { Module } from '@miiajs/core'
import { ConfigModule } from '@miiajs/config'
import { z } from 'zod'

const EnvSchema = z.object({
  PORT: z.string().default('3000'),
  DATABASE_URL: z.string(),
  JWT_SECRET: z.string(),
  DEBUG: z.string().default('false'),
})

@Module({
  imports: [
    ConfigModule.configure({ schema: EnvSchema }),
  ],
})
class AppModule {}

ConfigModule.configure() validates process.env against your schema at startup. If validation fails, the application throws with detailed error messages.

Using ConfigService

Inject ConfigService to access validated values:

import { Injectable, inject } from '@miiajs/core'
import { ConfigService } from '@miiajs/config'

@Injectable()
class DatabaseService {
  private config = inject(ConfigService)

  connect() {
    const url = this.config.getOrThrow('DATABASE_URL')
    const port = this.config.get('PORT') ?? '3000'
    // ...
  }
}

API

MethodReturnsOn missing key
get(key)T[K] | undefinedReturns undefined
getOrThrow(key)T[K]Throws Error

Factory configuration

Use a factory function to resolve config from DI:

import { DrizzleModule } from '@miiajs/drizzle'

@Module({
  imports: [
    ConfigModule.configure({ schema: EnvSchema }),
    DrizzleModule.configure((resolve) => {
      const config = resolve(ConfigService)
      return {
        dialect: 'postgres',
        connection: { url: config.getOrThrow('DATABASE_URL') },
      }
    }),
  ],
})
class AppModule {}

The resolve function gives access to the DI container, allowing modules to depend on each other's configuration.

Custom env source

By default, ConfigModule reads from process.env. You can pass a custom source:

ConfigModule.configure({
  schema: EnvSchema,
  env: {
    PORT: '8080',
    DATABASE_URL: 'postgres://localhost:5432/test',
    JWT_SECRET: 'test-secret',
  },
})

This is useful for testing or when loading from a custom source.

Schema requirements

The schema must implement a safeParse() method (ZodLike interface):

interface ZodLike<T = any> {
  safeParse(data: unknown):
    | { success: true; data: T }
    | { success: false; error: { issues: { message: string; path?: (string | number)[] }[] } }
}

This means you can use Zod, or implement a custom validation schema without any external dependency.