Agent skill

environment-variables

Use compile-time validated environment variables with t3-oss/env-nextjs. Ensures type-safe access to environment variables with automatic validation at build time. Use when accessing any environment variable or adding new environment configurations.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/development/environment-variables

SKILL.md

Environment Variables

Use type-safe, compile-time validated environment variables with automatic validation at build time using t3-oss/env-nextjs.

Overview

This project uses @t3-oss/env-nextjs to validate environment variables at build time, preventing runtime errors from missing or invalid configuration. All environment variables are defined in env.ts with Zod schemas and are validated when Next.js builds.

How It Works

  1. Build-Time Validation: next.config.mjs imports env.ts, triggering validation before the app builds
  2. Type Safety: TypeScript provides autocomplete and type checking for all environment variables
  3. Runtime Access: Import env from @/env to access validated variables anywhere in the app

File Structure

/env.ts                    # Environment variable schema and validation
/next.config.mjs           # Imports env.ts for build-time validation
/.env.local                # Local development environment variables
/.env.example              # Template showing all required variables

Usage Examples

Accessing Environment Variables

Before (process.env - not type-safe, no validation):

typescript
// ❌ No type checking, could be undefined
const apiKey = process.env.ANTHROPIC_API_KEY;

After (env - type-safe, validated):

typescript
// ✅ Type-safe, guaranteed to exist and be valid
import { env } from "@/env";

const apiKey = env.ANTHROPIC_API_KEY; // string (validated at build time)

Common Patterns

Server-side usage (Server Actions, API Routes):

typescript
import { env } from "@/env";

export async function createUser() {
  const supabase = createClient<Database>(
    env.NEXT_PUBLIC_SUPABASE_URL,
    env.SUPABASE_SECRET_KEY // Server-only variable
  );
}

Client-side usage (Components):

typescript
"use client";

import { env } from "@/env";

export function SupabaseProvider() {
  // Only NEXT_PUBLIC_* variables are available on client
  const client = createBrowserClient(
    env.NEXT_PUBLIC_SUPABASE_URL,
    env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY
  );
}

Adding New Environment Variables

When adding a new environment variable, follow these steps:

1. Add to .env.example and .env.local

bash
# .env.example
NEW_SERVICE_API_KEY=your-api-key-here
NEXT_PUBLIC_NEW_SERVICE_URL=https://api.example.com

2. Add to env.ts Schema

Determine if the variable is server-only or client-side (must start with NEXT_PUBLIC_):

Server-only variable:

typescript
// env.ts
export const env = createEnv({
  server: {
    // Add new server variable
    NEW_SERVICE_API_KEY: z.string().min(1),
    // ... existing variables
  },
  client: {
    // ... existing client variables
  },
  runtimeEnv: {
    // Add to runtimeEnv
    NEW_SERVICE_API_KEY: process.env.NEW_SERVICE_API_KEY,
    // ... existing mappings
  },
});

Client-side variable (NEXT_PUBLIC_*):

typescript
// env.ts
export const env = createEnv({
  server: {
    // ... existing server variables
  },
  client: {
    // Add new client variable
    NEXT_PUBLIC_NEW_SERVICE_URL: z.string().includes("://"),
    // ... existing client variables
  },
  runtimeEnv: {
    // Add to runtimeEnv
    NEXT_PUBLIC_NEW_SERVICE_URL: process.env.NEXT_PUBLIC_NEW_SERVICE_URL,
    // ... existing mappings
  },
});

3. Use in Your Code

typescript
import { env } from "@/env";

const apiKey = env.NEW_SERVICE_API_KEY; // Type-safe access

Validation Rules

Common Zod Validators

typescript
// Required string with minimum length
API_KEY: z.string().min(1)

// Optional string
OPTIONAL_KEY: z.string().optional()

// URL validation
SERVICE_URL: z.string().includes("://")

// Email validation
EMAIL: z.string().includes("@")

// Enum validation
NODE_ENV: z.enum(["development", "production", "test"])

// Number validation
PORT: z.coerce.number().min(1000).max(9999)

Special Cases

Email with optional display name:

typescript
DEV_EMAIL_FROM: z.string().includes("@").or(z.string().regex(/^.+\s<.+@.+>$/))

Optional environment variable:

typescript
ADMIN_EMAIL: z.string().includes("@").optional()

Build-Time Validation

When you run bun run build or bun run dev, Next.js automatically validates all environment variables:

bash
# If validation fails:
❌ Invalid environment variables:
  ANTHROPIC_API_KEY: Required
  RESEND_API_KEY: Required

Skip Validation (CI/CD)

In CI/CD environments where environment variables aren't available during build:

bash
SKIP_ENV_VALIDATION=true bun run build

Important Notes

  1. Never commit .env.local or .env.production - these files are in .gitignore
  2. Always update .env.example when adding new variables
  3. Server variables are only accessible on the server (API routes, Server Components, Server Actions)
  4. Client variables must be prefixed with NEXT_PUBLIC_ and are exposed to the browser
  5. Build fails if any required environment variable is missing or invalid

Reference

  • Schema definition: env.ts
  • Build validation: next.config.mjs (imports env.ts)
  • Example template: .env.example
  • Documentation: https://env.t3.gg/docs/nextjs

Didn't find tool you were looking for?

Be as detailed as possible for better results