Validation
Fail-fast validation of required secrets.
The require() method ensures critical secrets exist before your application runs, failing fast with a clear error instead of crashing later with cryptic undefined errors.
Recommended: Validate at Initialization#
The best place to validate secrets is in your lib/redenv.ts file, right when initializing the client. Since init() now returns the Secrets object, you can validate immediately at app startup:
import { Redenv } from "@redenv/client";
export const redenv = new Redenv({
project: process.env.REDENV_PROJECT!,
tokenId: process.env.REDENV_TOKEN_ID!,
token: process.env.REDENV_TOKEN_KEY!,
upstash: {
url: process.env.UPSTASH_REDIS_URL!,
token: process.env.UPSTASH_REDIS_TOKEN!,
},
environment: process.env.NODE_ENV || "development",
});
// Initialize AND validate in one place
await redenv.init().require(
"DATABASE_URL",
"JWT_SECRET",
"STRIPE_SECRET_KEY",
); Tip
Why here? This runs the moment your app imports lib/redenv.ts. If any
secrets are missing, your app fails immediately — before any routes, services,
or database connections are attempted.
If any of the specified keys are missing, a RedenvError is thrown:
RedenvError: Missing required secrets: JWT_SECRET, STRIPE_SECRET_KEYBasic Usage#
const secrets = await redenv.load();
// Throws immediately if any secrets are missing
secrets.require("DATABASE_URL", "JWT_SECRET", "STRIPE_KEY");Chaining#
The require() method returns this, enabling method chaining:
const secrets = await redenv.load();
const dbUrl = secrets.require("DATABASE_URL", "JWT_SECRET").DATABASE_URL;With Scoping#
Combine with scope() to validate scoped configurations:
const secrets = await redenv.load();
// Validate and scope in one flow
const aws = secrets
.require("AWS_ACCESS_KEY", "AWS_SECRET_KEY", "AWS_REGION")
.scope("AWS_");
console.log(aws.ACCESS_KEY); // Already validatedAdditional Patterns#
Module-Level Validation#
import { redenv } from "../lib/redenv";
import Stripe from "stripe";
export async function getStripeClient() {
const secrets = await redenv.load();
// Validate Stripe-specific secrets
secrets.require("STRIPE_SECRET_KEY", "STRIPE_WEBHOOK_SECRET");
return new Stripe(secrets.STRIPE_SECRET_KEY, {
apiVersion: "2024-01-01",
});
}Conditional Requirements#
const secrets = await redenv.load();
// Always required
secrets.require("DATABASE_URL", "JWT_SECRET");
// Conditionally required
if (process.env.NODE_ENV === "production") {
secrets.require("SENTRY_DSN", "DATADOG_API_KEY");
}Error Handling#
import { RedenvError } from "@redenv/client";
try {
const secrets = await redenv.load();
secrets.require("CRITICAL_SECRET");
} catch (error) {
if (error instanceof RedenvError && error.code === "SECRET_NOT_FOUND") {
console.error("Missing secrets:", error.message);
process.exit(1);
}
throw error;
}Why Use require()?#
Warning
Without validation:
const apiKey = secrets.API_KEY;
// Later...
fetch(url, { headers: { Authorization: apiKey } });
// Error: Cannot read property 'Authorization' of undefined
// Or worse: silent 401 errors with no clear causeInfo
With validation:
.require("API_KEY");
// Fails immediately with: "Missing required secrets: API_KEY"
// Clear, actionable error message Fail-fast validation:
- Catches configuration errors at startup, not at runtime
- Provides clear, actionable error messages
- Prevents cascading failures and debugging headaches