Managing TypeScript Application Configuration: A Complete Guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

TypeScript Application Configuration: From Simple to Complex

Any modern application requires flexible and secure configuration. Whether it's API keys, database connection parameters, server ports, or feature flags — configuration should be separated from code, easy to read, and validated at startup. In the world of TypeScript, this task has its own specifics: configuration typing provides autocompletion and prevents runtime errors. In this article, we will cover best practices, popular libraries, and tools for managing TypeScript application configuration.



Why not use process.env directly?

At first glance, reading environment variables via process.env seems like a simple solution. However, this approach has significant drawbacks:

  • Lack of typing: all values are strings, even if logically they are numbers or booleans.
  • Risk of typos: it's easy to write process.env.DB_HOTS instead of DB_HOST and get undefined.
  • No validation: if a required variable is not set, the application will fail at the most unexpected moment, not at startup.

Proper configuration solves all these problems.



The dotenv library and its TypeScript wrappers

The de facto standard for loading .env files is the dotenv library. For TypeScript, it's convenient to use dotenv-flow or dotenv-expand, which support multiple environments (development, staging, production).

// Installation// npm install dotenv dotenv-expand

// config/env.tsimport dotenv from 'dotenv';import dotenvExpand from 'dotenv-expand';

const myEnv = dotenv.config({ path: `.env.${process.env.NODE_ENV || 'development'}` });dotenvExpand.expand(myEnv);

After calling this function, all variables from the .env file will be available via process.env, but we still don't have types.



Schema validation with Zod

Zod is a powerful library for declarative schema validation with first-class TypeScript support. It is ideal for configuration:

// config/schema.tsimport { z } from 'zod';

const envSchema = z.object({ NODE_ENV: z.enum(['development', 'production', 'test']).default('development'), PORT: z.coerce.number().positive().default(3000), DATABASE_URL: z.string().url(), JWT_SECRET: z.string().min(32), REDIS_HOST: z.string().default('localhost'), REDIS_PORT: z.coerce.number().default(6379), FEATURE_NEW_UI: z .string() .transform((val) => val === 'true') .default('false'),});

export type EnvConfig = z.infer<typeof envSchema>;

Now we can safely parse and validate the environment at startup:

// config/index.tsimport { envSchema, EnvConfig } from './schema';

let config: EnvConfig;

export function loadConfig(): EnvConfig { if (config) return config; // caching

const result = envSchema.safeParse(process.env); if (!result.success) { console.error('❌ Invalid environment variables:', result.error.flatten().fieldErrors); process.exit(1); } config = result.data; return config;}

export function getConfig(): EnvConfig { if (!config) throw new Error('Config not loaded. Call loadConfig() first.'); return config;}


The Conf library for managing application configuration

If your application requires not only reading but also writing configuration (e.g., user settings, cache), check out conf by Sindre Sorhus. It stores data in a JSON file and is fully typed.

// Installation// npm install conf

import Conf from 'conf';

interface AppConfig { lastOp

Recommendations