ShipkitShipkit
DocsFeaturesPricing
Get Shipkit

Development GuideEnvironment VariablesError HandlingShipKit Documentation

snippet-intro
⌘K

    Environment Variables

    Managing environment variables in ShipKit

    Environment Variables

    ShipKit uses Zod for type-safe environment variable validation. This ensures runtime safety and provides excellent developer experience with TypeScript integration.

    Quick Setup

    1. Copy the example environment file:
    cp .env.example .env.local
    
    1. Generate required secrets:
    # Generate AUTH_SECRET
    openssl rand -base64 32
    
    # Generate PAYLOAD_SECRET
    openssl rand -base64 32
    

    File Structure

    • .env.local - Local development variables (not committed)
    • .env.test - Test environment variables (committed)
    • .env.example - Example variables template (committed)
    • env.schema.ts - TypeScript schema (committed)

    Required Variables

    Core Authentication

    # Base URL for authentication (required)
    AUTH_URL="http://localhost:3000"
    
    # JWT secret for session management (required)
    # Generate with: openssl rand -base64 32
    AUTH_SECRET=""
    

    OAuth Providers

    GitHub

    # GitHub OAuth credentials (required)
    # Get from: https://github.com/settings/developers
    AUTH_GITHUB_ID=""
    AUTH_GITHUB_SECRET=""
    

    Discord

    # Discord OAuth credentials (required)
    # Get from: https://discord.com/developers/applications
    AUTH_DISCORD_ID=""
    AUTH_DISCORD_SECRET=""
    

    Google

    # Google OAuth credentials (required)
    # Get from: https://console.cloud.google.com/apis/credentials
    AUTH_GOOGLE_ID=""
    AUTH_GOOGLE_SECRET=""
    

    Database

    # PostgreSQL connection string (required)
    # Format: postgresql://USER:PASSWORD@HOST:PORT/DATABASE
    DATABASE_URL="postgresql://postgres:password@localhost:5432/shipkit"
    

    Email Service

    # Resend API key (required)
    # Get from: https://resend.com/api-keys
    RESEND_API_KEY=""
    

    Payments

    # LemonSqueezy API credentials (required)
    # Get from: https://app.lemonsqueezy.com/settings/api
    LEMONSQUEEZY_API_KEY=""
    LEMONSQUEEZY_STORE_ID=""
    LEMONSQUEEZY_WEBHOOK_SECRET=""
    

    Content Management

    # Payload CMS secret (required)
    # Generate with: openssl rand -base64 32
    PAYLOAD_SECRET=""
    

    Node Environment

    # Node environment (required)
    # Values: development, test, production
    NODE_ENV="development"
    

    Type Safety

    Environment variables are validated using Zod schemas:

    // src/env.schema.ts
    import { z } from "zod";
    
    export const envSchema = z.object({
      // Core Auth
      AUTH_URL: z.string().url(),
      AUTH_SECRET: z.string().min(1),
    
      // OAuth Providers
      AUTH_GITHUB_ID: z.string().min(1),
      AUTH_GITHUB_SECRET: z.string().min(1),
      AUTH_DISCORD_ID: z.string().min(1),
      AUTH_DISCORD_SECRET: z.string().min(1),
      AUTH_GOOGLE_ID: z.string().min(1),
      AUTH_GOOGLE_SECRET: z.string().min(1),
    
      // Database
      DATABASE_URL: z.string().min(1),
    
      // Email
      RESEND_API_KEY: z.string().min(1),
    
      // Payments
      LEMONSQUEEZY_API_KEY: z.string().min(1),
      LEMONSQUEEZY_STORE_ID: z.string().min(1),
      LEMONSQUEEZY_WEBHOOK_SECRET: z.string().min(1),
    
      // CMS
      PAYLOAD_SECRET: z.string().min(1),
    
      // Node Environment
      NODE_ENV: z.enum(["development", "test", "production"]),
    });
    
    export type Env = z.infer<typeof envSchema>;
    

    Environment Management

    Local Development

    1. Initial setup:
    cp .env.example .env.local
    
    1. Update variables:
    • Edit .env.local directly
    • Use pnpm db:sync to sync database configuration

    Production (Vercel)

    1. Add variables:
    vercel env add MY_NEW_VAR
    
    1. Remove variables:
    vercel env rm MY_VAR
    
    1. Pull variables:
    vercel env pull .env.production
    

    Best Practices

    1. Security

      • Never commit .env.local or .env.production
      • Use strong, unique secrets for each environment
      • Rotate secrets regularly
      • Use different values for development and production
    2. Documentation

      • Keep .env.example updated with all variables
      • Document each variable's purpose and format
      • Include links to external service dashboards
    3. Type Safety

      • Always update env.schema.ts when adding variables
      • Use strict validation rules
      • Handle required variables explicitly
    4. Organization

      • Group related variables together
      • Use clear, descriptive names
      • Follow naming conventions consistently

    Common Issues

    1. Database Connection

      • Check DATABASE_URL format
      • Verify database credentials
      • Confirm database server is running
    2. OAuth Configuration

      • Verify callback URLs match AUTH_URL
      • Check provider credentials
      • Confirm OAuth app settings
    3. Email Service

      • Validate RESEND_API_KEY format
      • Check API key permissions
      • Monitor email delivery logs
    4. Payment Integration

      • Verify LemonSqueezy credentials
      • Check webhook configuration
      • Test payment flows in sandbox mode

    Security Considerations

    1. Secret Management

      • Use a password manager for secrets
      • Never share secrets in plain text
      • Rotate compromised secrets immediately
    2. Access Control

      • Limit access to production variables
      • Use separate accounts for staging/production
      • Audit variable access regularly
    3. Monitoring

      • Log environment changes
      • Monitor for unauthorized access
      • Set up alerts for critical changes

    Validation Scripts

    // scripts/validate-env.ts
    import { envSchema } from "../src/env.schema";
    
    function validateEnv() {
      try {
        envSchema.parse(process.env);
        console.log("✅ Environment variables are valid");
      } catch (error) {
        console.error("❌ Invalid environment variables:", error);
        process.exit(1);
      }
    }
    
    validateEnv();
    

    Run validation:

    pnpm tsx scripts/validate-env.ts