Configuration
Validated, typed configuration that fails fast at startup.
defineConfig pairs a name with a schema and returns a typed injection token.
import { defineConfig } from '@sukujs/core';
import { z } from 'zod';
export const Env = defineConfig(
'env',
z.object({
PORT: z.coerce.number().int().positive().default(3000),
DATABASE_URL: z.url(),
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
}),
);Add Env.load() to your features to validate the environment when the application starts.
const app = await Suku.create({ features: [Env.load(), UsersFeature], adapter: nodeAdapter() });
await app.listen(app.get(Env).PORT);Inject it with the token.
import type { Infer } from '@sukujs/core';
@Service()
export class Database {
constructor(@Inject(Env) private readonly env: Infer<typeof Env.schema>) {}
}
route.get('/info', {
services: { env: Env },
handle: ({ env }) => ({ logLevel: env.LOG_LEVEL }), // typed from the schema
});Failing fast
If the environment is invalid, Suku.create rejects before anything listens, and every
problem is listed at once.
ConfigError: Invalid configuration "env":
- PORT: Invalid input: expected number, received NaN
- DATABASE_URL: Invalid input: expected string, received undefinedOther sources
load() reads process.env by default. Pass any object instead.
Env.load({ ...process.env, ...(await readSecrets()) });Env.parse() validates and returns the value without creating a feature, for scripts that run
outside the container.
Several configs
Define one per concern. Each is its own token.
export const Mail = defineConfig('mail', z.object({ SMTP_URL: z.url() }));
features: [Env.load(), Mail.load()];