Tür Güvenli Ortam Yapılandırması ve Çalışma Zamanı Doğrulaması
Ortam değişkenlerini ve dış girdileri, şema kütüphanelerini statik türlere çıkararak çalışma zamanında doğrulayın.
Tür Güvenli Ortam Yapılandırması ve Çalışma Zamanı Doğrulaması, CoddyKit'te ücretsiz bir Node.js Backend Development Bootcamp dersidir. Bu, 4 dersinin 3. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, Node.js Backend Development Bootcamp öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. Node.js Backend Development Bootcamp kursu toplamda 4 dersten oluşur.
Bu dersin bazı bölümleri henüz çevrilmemiş olup İngilizce olarak gösterilmektedir.
Why Validate process.env?
In Node.js, every value on process.env is a string or undefined — the runtime gives you no guarantees.
process.env.PORTmight be"3000","", or missing entirely.- A typo like
DATABSE_URLsilently yieldsundefined. - TypeScript types
process.envasRecord<string, string | undefined>, so it can't catch missing keys.
Reading config ad-hoc throughout your app means crashes surface deep inside request handlers — long after startup. The fix: validate once at boot and fail fast with a clear message.
// Untyped, unsafe access scattered everywhere
const port = process.env.PORT; // string | undefined
const dbUrl = process.env.DATABASE_URL; // string | undefined
console.log(typeof port); // "string" or "undefined"
console.log(Number(process.env.MISSING)); // NaN — silent failureSchema Libraries and Type Inference
A schema library lets you describe the shape and constraints of data once, then validate at runtime AND infer a static TypeScript type from the same definition.
- Popular choices: Zod, Valibot, ArkType, TypeBox.
- One source of truth — the schema — produces both the runtime check and the compile-time type.
- No duplicated
interfacethat can drift out of sync.
We'll use Zod, the most common in the Node.js ecosystem. z.infer<typeof schema> extracts the type the schema validates.
import { z } from "zod";
const UserSchema = z.object({
id: z.number().int(),
email: z.string().email(),
});
// Static type inferred from the runtime schema
type User = z.infer<typeof UserSchema>;
// type User = { id: number; email: string }A First Env Schema
Let's describe the environment our service needs. Because process.env values are always strings, the schema must coerce numeric fields and constrain string fields.
z.coerce.number()turns"3000"into3000.z.enum([...])restricts a value to a fixed set.- Chaining like
.min()/.url()adds runtime constraints.
Define the schema in its own module (e.g. src/env.ts) so it's imported once at startup.
import { z } from "zod";
export const EnvSchema = z.object({
NODE_ENV: z.enum(["development", "test", "production"]),
PORT: z.coerce.number().int().positive().default(3000),
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
});Parsing at Startup
Call schema.parse(process.env) once, at the top of your entry file. If validation fails, Zod throws a ZodError and the process exits before serving any traffic.
parse()returns a fully typed, validated object.- Coerced and defaulted values are already applied.
- Export the result so the rest of the app imports a typed
envobject instead of touchingprocess.envdirectly.
import { z } from "zod";
import { EnvSchema } from "./env-schema";
export const env = EnvSchema.parse(process.env);
// env.PORT is number, env.NODE_ENV is a narrowed union
const server = createServer();
server.listen(env.PORT, () => {
console.log(`Listening on ${env.PORT} in ${env.NODE_ENV}`);
});safeParse for Friendly Errors
A raw ZodError stack trace is noisy. Use safeParse to get a result object you can format into a readable startup message, then exit deliberately.
safeParsereturns{ success: true, data }or{ success: false, error }— it never throws.error.flatten().fieldErrorsgroups messages per field.- Exit with
process.exit(1)so orchestrators (Docker, PM2, k8s) see a failed boot.
import { z } from "zod";
const EnvSchema = z.object({
PORT: z.coerce.number().int().positive(),
DATABASE_URL: z.string().url(),
});
const parsed = EnvSchema.safeParse(process.env);
if (!parsed.success) {
console.error("Invalid environment variables:");
console.error(parsed.error.flatten().fieldErrors);
process.exit(1);
}
export const env = parsed.data;A Standalone, Runnable Example
Here is a self-contained demonstration of the validate-then-infer pattern using a plain object instead of process.env, so an online judge can run it with no setup.
It shows coercion, a default, an enum, and a friendly error path — the same techniques you'd apply to real environment loading.
import { z } from "zod";
const Schema = z.object({
NODE_ENV: z.enum(["development", "production"]).default("development"),
PORT: z.coerce.number().int().positive(),
});
function loadConfig(raw) {
const result = Schema.safeParse(raw);
if (!result.success) {
throw new Error(JSON.stringify(result.error.flatten().fieldErrors));
}
return result.data;
}
const config = loadConfig({ PORT: "8080" });
console.log(config); // { NODE_ENV: 'development', PORT: 8080 }
console.log(typeof config.PORT); // numberLoading .env Files with ESM
Locally you store config in a .env file. The library dotenv reads it into process.env. With ESM and TypeScript, load it before any module that reads config.
- Modern Node (v20.6+) has a built-in
--env-file=.envflag — no dependency needed. - If you use
dotenv, calldotenv/configat the very top, since ESM imports are hoisted and evaluated first. - Never commit real secrets; commit a
.env.exampledocumenting required keys.
// Option A: built-in (Node 20.6+), no import needed
// $ node --env-file=.env dist/index.js
// Option B: dotenv — must run first
import "dotenv/config";
import { EnvSchema } from "./env-schema";
export const env = EnvSchema.parse(process.env);Reusing the Schema for Request Input
The exact same approach validates untrusted runtime input — request bodies, query params, webhook payloads. Network data is just as untyped as process.env.
- Define a schema per endpoint, then
parsethe incoming JSON. - On failure, respond with
400instead of crashing. - The parsed result is fully typed for the rest of the handler.
import { z } from "zod";
const CreateUserBody = z.object({
email: z.string().email(),
age: z.coerce.number().int().min(0).optional(),
});
function handleCreateUser(rawBody, res) {
const result = CreateUserBody.safeParse(rawBody);
if (!result.success) {
res.status(400).json({ errors: result.error.flatten() });
return;
}
const body = result.data; // { email: string; age?: number }
// ...persist body
}Transforms and Derived Config
Schemas can transform values during parsing, producing config that's ready to use. This keeps conversion logic next to the validation rule.
.transform()maps a validated value into a new shape.- Comma-separated env strings become arrays; flags become booleans.
- The inferred type reflects the transformed output, not the raw input.
import { z } from "zod";
const EnvSchema = z.object({
// "a.com,b.com" -> ["a.com", "b.com"]
CORS_ORIGINS: z.string()
.transform((s) => s.split(",").map((o) => o.trim()))
.pipe(z.array(z.string().url())),
// "true"/"false" string -> boolean
ENABLE_CACHE: z
.enum(["true", "false"])
.transform((v) => v === "true")
.default("false"),
});Cross-Field Rules with refine
Sometimes validity depends on relationships between fields — e.g. in production a secret must be set, but locally a default is fine. Use .refine() or .superRefine() on the object schema.
- The check runs after individual fields parse.
- You attach a custom message and a
pathso the error points at the right field. - This encodes business rules that a flat per-field schema cannot.
import { z } from "zod";
const EnvSchema = z
.object({
NODE_ENV: z.enum(["development", "production"]),
SENTRY_DSN: z.string().url().optional(),
})
.refine(
(e) => e.NODE_ENV !== "production" || !!e.SENTRY_DSN,
{ message: "SENTRY_DSN is required in production", path: ["SENTRY_DSN"] }
);Exporting a Typed Config Singleton
The end goal: the rest of your codebase never touches process.env. It imports a single validated, typed env object.
- Centralizing access means TypeScript autocompletes every key and flags typos at compile time.
- Refactoring a variable name becomes a single-file change.
- Tests can import a schema and feed mock objects instead of mutating global state.
// src/config.ts
import "dotenv/config";
import { z } from "zod";
const EnvSchema = z.object({
NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
PORT: z.coerce.number().int().positive().default(3000),
DATABASE_URL: z.string().url(),
});
const parsed = EnvSchema.safeParse(process.env);
if (!parsed.success) {
console.error("❌ Invalid env:", parsed.error.flatten().fieldErrors);
process.exit(1);
}
export const env = Object.freeze(parsed.data);
// elsewhere: import { env } from "./config";Quick Check
Test your understanding of the type-safe config pattern.
Recap
You learned to make configuration and external input type-safe in modern Node.js:
- Why:
process.envand network data are untyped strings; validate once and fail fast. - Schemas: a library like Zod gives runtime validation plus inferred static types from one definition (
z.infer). - Env loading: coerce numbers, constrain with enums/defaults, load
.envvia--env-fileordotenv/configbefore reading. - safeParse: format
error.flatten().fieldErrorsandprocess.exit(1)on failure. - Beyond env: reuse schemas for request bodies, add
.transform()for derived config and.refine()for cross-field rules. - Result: export one frozen, typed
envsingleton the whole app imports.
Sıkça Sorulan Sorular
“Tür Güvenli Ortam Yapılandırması ve Çalışma Zamanı Doğrulaması” dersi ücretsiz mi?
Evet — “Tür Güvenli Ortam Yapılandırması ve Çalışma Zamanı Doğrulaması” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve Node.js Backend Development Bootcamp kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. Node.js Backend Development Bootcamp kursu toplamda 4 dersten oluşur.
“Tür Güvenli Ortam Yapılandırması ve Çalışma Zamanı Doğrulaması” dersinde ne öğreneceğim?
Ortam değişkenlerini ve dış girdileri, şema kütüphanelerini statik türlere çıkararak çalışma zamanında doğrulayın. Node.js Backend Development Bootcamp ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
Node.js Backend Development Bootcamp öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te Node.js Backend Development Bootcamp, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 3. dersidir.
“Tür Güvenli Ortam Yapılandırması ve Çalışma Zamanı Doğrulaması” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu Node.js Backend Development Bootcamp dersinde kod yazıp çalıştırabilir miyim?
Evet. Her Node.js Backend Development Bootcamp dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- CommonJS'ten Yerel ES Modüllerine Geçiş
- Node Arka Uç Projeleri için tsconfig Yapılandırması
- Tür Güvenli Ortam Yapılandırması ve Çalışma Zamanı Doğrulaması
- tsx, Hızlı Yeniden Yükleme ve Kaynak Eşlemeleriyle Hızlı Yineleme