Claude Code CommandNextjs Vercel45 installs

Vercel Env Sync

Synchronize environment variables between local development and Vercel deployments

Install with the Claude Code Templates CLI
$ npx claude-code-templates@latest --command="nextjs-vercel/vercel-env-sync" --yes

Requires Claude Code. The command adds this command to your project's .claudedirectory — nothing runs on ToolZip's servers.

What's inside this command

Component source (preview)

Vercel Environment Sync

Sync Operation: $ARGUMENTS

Current Environment Analysis

Local Environment

  • Environment files:
- @.env.local (if exists)

- @.env.development (if exists)

- @.env.production (if exists)

- @.env (if exists)

  • Environment example: @.env.example (if exists)
  • Vercel config: @vercel.json (if exists)

Project Status

  • Vercel CLI status: !vercel --version 2>/dev/null || echo "Vercel CLI not installed"
  • Current project: !vercel project ls 2>/dev/null | head -5 || echo "Not linked to Vercel project"
  • Git status: !git status --porcelain | head -5

Environment Synchronization Strategy

1. Environment File Analysis

// Environment file structure analysis
interface EnvironmentConfig {
  development: Record<string, string>;
  preview: Record<string, string>;
  production: Record<string, string>;
}

const environmentFiles = {
  '.env.local': 'Local development overrides',
  '.env.development': 'Development environment',
  '.env.staging': 'Staging/preview environment', 
  '.env.production': 'Production environment',
  '.env': 'Default environment (committed to git)',
  '.env.example': 'Environment template (safe to commit)',
};

2. Vercel Environment Management

# List all environment variables for all environments
vercel env ls

# List environment variables for specific environment
vercel env ls --environment=production
vercel env ls --environment=preview
vercel env ls --environment=development

# Pull environment variables from Vercel
vercel env pull .env.vercel

# Add new environment variable
vercel env add [name] [environment]

# Remove environment variable
vercel env rm [name] [environment]

Synchronization Operations

1. Pull Environment Variables from Vercel

#!/bin/bash
# Pull environments from Vercel

echo "🔄 Pulling environment variables from Vercel..."

# Create backup of existing files
if [ -f .env.local ]; then
  cp .env.local .env.local.backup.$(date +%Y%m%d_%H%M%S)
  echo "📦 Backup created for .env.local"
fi

# Pull from Vercel (creates .env.local by default)
vercel env pull .env.local

if [ $? -eq 0 ]; then
  echo "✅ Successfully pulled environment variables"
  echo "📁 Variables saved to .env.local"
  
  # Show summary
  echo ""
  echo "📊 Environment Variables Summary:"
  echo "================================"
  grep -c "=" .env.local 2>/dev/null && echo "Total variables: $(grep -c "=" .env.local)"
  
  # List variable names (hide values for security)
  echo ""
  echo "🔑 Variable Names:"
  grep "^[A-Z]" .env.local | cut -d'=' -f1 | sort
else
  echo "❌ Failed to pull environment variables"
  exit 1
fi

2. Push Environment Variables to Vercel

#!/bin/bash
# Push environment variables to Vercel

echo "🚀 Pushing environment variables to Vercel..."

# Check if environment files exist
ENV_FILES=(".env.production" ".env.staging" ".env.development")
FOUND_FILES=()

for file in "${ENV_FILES[@]}"; do
  if [ -f "$file" ]; then
    FOUND_FILES+=("$file")
  fi
done

if [ ${#FOUND_FILES[@]} -eq 0 ]; then
  echo "❌ No environment files found to push"
  echo "💡 Expected files: ${ENV_FILES[*]}"
  exit 1
fi

# Push each environment file
for file in "${FOUND_FILES[@]}"; do
  echo "📤 Processing $file..."
  
  # Determine target environment
  if [[ "$file" == *"production"* ]]; then
    ENV="production"
  elif [[ "$file" == *"staging"* ]]; then
    ENV="preview"  # Vercel uses 'preview' for staging
  elif [[ "$file" == *"development"* ]]; then
    ENV="development"
  else
    ENV="development"  # Default
  fi
  
  echo "🎯 Pushing to $ENV environment..."
  
  # Read variables from file and push to Vercel
  while IFS='=' read -r key value; do
    # Skip empty lines and comments
    if [[ -z "$key" || "$key" =~ ^#.* ]]; then
      continue
    fi
    
    # Remove quotes from value if present
    value=$(echo "$value" | sed 's/^"\(.*\)"$/\1/' | sed "s/^'\(.*\)'$/\1/")
    
    echo "  🔑 Setting $key..."
    echo "$value" | vercel env add "$key" "$ENV" --force
    
  done < "$file"
  
  echo "✅ Completed $file -> $ENV"
  echo ""
done

echo "🎉 All environment variables pushed successfully!"

3. Environment Validation

// Environment validation script
interface ValidationRule {
  name: string;
  required: boolean;
  pattern?: RegExp;
  description: string;
}

const validationRules: ValidationRule[] = [
  {
    name: 'DATABASE_URL',
    required: true,
    pattern: /^(postgresql|mysql|sqlite):\/\/.+/,
    description: 'Database connection string',
  },
  {
    name: 'NEXTAUTH_SECRET',
    required: true,
    pattern: /.{32,}/,
    description: 'NextAuth.js secret key (min 32 characters)',
  },
  {
    name: 'NEXTAUTH_URL',
    required: true,
    pattern: /^https?:\/\/.+/,
    description: 'NextAuth.js canonical URL',
  },
  {
    name: 'API_KEY',
    required: false,
    pattern: /^[A-Za-z0-9_-]+$/,
    description: 'API key for external services',
  },
];

function validateEnvironment(envFile: string): ValidationResult {
  const errors: string[] = [];
  const warnings: string[] = [];
  const env = readEnvironmentFile(envFile);
  
  // Check required variables
  validationRules.forEach(rule => {
    const value = env[rule.name];
    
    if (rule.required && !value) {
      errors.push(`Missing required variable: ${rule.name}`);
      return;
    }
    
    if (value && rule.pattern && !rule.pattern.test(value)) {
      errors.push(`Invalid format for ${rule.name}: ${rule.description}`);
    }
  });
  
  // Check for common issues
  Object.entries(env).forEach(([key, value]) => {
    // Check for placeholder values
    if (value === 'your-secret-here' || value === 'change-me') {
      warnings.push(`Placeholder value detected for ${key}`);
    }
    
    // Check for potentially committed secrets
    if (key.includes('SECRET') || key.includes('PRIVATE')) {
      if (value.length < 16) {
        warnings.push(`${key} appears to be too short for a secret`);
      }
    }
  });
  
  return {
    valid: errors.length === 0,
    errors,
    warnings,
  };
}

function readEnvironmentFile(filePath: string): Record<string, string> {
  // Implementation to read and parse environment file
  return {};
}

interface ValidationResult {
  valid: boolean;
  errors: string[];
  warnings: string[];
}

4. Environment Backup and Restore

#!/bin/bash
# Backup and restore environment variables

BACKUP_DIR=".env-backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

backup_environment() {
  echo "📦 Creating environment backup..."
  
  mkdir -p "$BACKUP_DIR"
  
  # Backup local files
  for file in .env.local .env.development .env.staging .env.production; do
    if [ -f "$file" ]; then
      cp "$file" "$BACKUP_DIR/${file}.${TIMESTAMP}"
      echo "✅ Backed up $file"
    fi
  done
  
  # Backup Vercel environment variables
  echo "📤 Backing up Vercel environment variables..."
  
  for env in production preview development; do
    vercel env ls --environment="$env" > "$BACKUP_DIR/vercel-${env}.${TIMESTAMP}.txt"
    echo "✅ Backed up Vercel $env environment"
  done
  
  echo "🎉 Backup completed in $BACKUP_DIR/"
  ls -la "$BACKUP_DIR/" | grep "$TIMESTAMP"
}

restore_environment() {
  local backup_timestamp="$1"
  
  if [ -z "$backup_timestamp" ]; then
    echo "❌ Please specify backup timestamp"
    echo "💡 Available backups:"
    ls -1 "$BACKUP_DIR/" | grep -E "\.env" | cut -d'.' -f3 | sort -u
    exit 1
  fi
  
  echo "🔄 Restoring environment from backup $backup_timestamp..."
  
  # Restore local files
  for file in .env.local .env.development .env.staging .env.production; do
    backup_file="$BACKUP_DIR/${file}.${backup_timestamp}"
    if [ -f "$backup_file" ]; then
      cp "$backup_file" "$file"
      echo "✅ Restored $file"
    fi
  done
  
  echo "🎉 Environment restored from backup"
}

# Usage functions
case "$1" in
  backup)
    backup_environment
    ;;
  restore)
    restore_environment "$2"
    ;;
  *)
    echo "Usage: $0 {backup|restore} [timestamp]"
    exit 1
    ;;
esac

Advanced Synchronization Features

1. Environment Diff and Comparison

// Environment comparison tool
interface EnvironmentDiff {
  added: string[];
  removed: string[];
  modified: Array<{
    key: string;
    local: string;
    remote: string;
  }>;
  unchanged: string[];
}

function compareEnvironments(
  local: Record<string, string>,
  remote: Record<string, string>
): EnvironmentDiff {
  const diff: EnvironmentDiff = {
    added: [],
    removed: [],
    modified: [],
    unchanged: [],
  };
  
  const allKeys = new Set([...Object.keys(local), ...Object.keys(remote)]);
  
  allKeys.forEach(key => {
    if (!(key in local)) {
      diff.added.push(key);
    } else if (!(key in remote)) {
      diff.removed.push(key);
    } else if (local[key] !== remote[key]) {
      diff.modified.push({
        key,
        local: local[key],
        remote: remote[key],
      });
    } else {
      diff.unchanged.push(key);
    }
  });
  
  return diff;
}

// Generate diff report
function generateDiffReport(diff: EnvironmentDiff): string {
  let report = '# Environment Variables Comparison\n\n';
  
  if (diff.added.length > 0) {
    report += '## ➕ Variables in Remote (not in Local)\n';
    diff.added.forEach(key => {
      report += `- \`${key}\`\n`;
    });
    report += '\n';
  }
  
  if (diff.removed.length > 0) {
    report += '## ➖ Variables in Local (not in Remote)\n';
    diff.removed.forEach(key => {
      report += `- \`${key}\`\n`;
    });
    report += '\n';
  }
  
  if (diff.modified.length > 0) {
    report += '## 🔄 Modified Variables\n';
    diff.modified.forEach(({ key, local, remote }) => {
      report += `### \`${key}\`\n`;
      report += `- **Local**: \`${maskSensitive(local)}\`\n`;
      report += `- **Remote**: \`${maskSensitive(remote)}\`\n\n`;
    });
  }
  
  if (diff.unchanged.length > 0) {
    report += `## ✅ Unchanged Variables (${diff.unchanged.length})\n`;
    report += `${diff.unchanged.map(key => `- \`${key}\``).join('\n')}\n\n`;
  }
  
  return report;
}

function maskSensitive(value: string): string {
  // Mask sensitive values for security
  if (value.length <= 8) {
    return '*'.repeat(value.length);
  }
  return `${value.substring(0, 4)}${'*'.repeat(value.length - 8)}${value.substring(value.length - 4)}`;
}

2. Environment Template Generation

``typescript

// Generate .env.example from existing environment

function generateEnvExample(envFile: string): string {

const env = readEnvironmentFile(envFile);

let template = '# Environment Variables Template\n';

template += '# Copy this file to .env.local and fill in the values\n\n';

const categories = categorizeVariables(env);

Object.entries(categories).forEach(([category, variables]) => {

template += # ${category.toUpperCase()}\n;

variables.forEach(({ key, description, example }) => {

if (description) {

template += # ${description}\n;

}

template += ${key}=${example || 'your-value-here'}\n\n`;

});

});

return template;

}

function categorizeVariables(env: Record) {

const categories: Record

key: string;

description?: string;

example?: string;

}>> = {

database: [],

authentication: [],

external_apis: [],

configuration: [],

};

Object.keys(env).forEach(key => {

if (key.includes('DATABASE') || key.includes('DB_')) {

categories.database.push({ key, description: getDatabaseDescription(key) });

} else if (key.includes('AUTH') || key.includes('SECRET')) {

categories.authentication.push({ key, description: getAuthDescription(key) });

} else if (key.includes('API_KEY') || key.includes('_TOKEN')) {

categories.external_apis.push({ key, description: getApiDescription(key) });

} else {

categories.configuration.push({ key, description: getConfigDescription(key) });

}

});

return categories;

}

function ge

Preview truncated. View the full source on GitHub →

Type
Command
Category
Nextjs Vercel
Installs
45
Source
GitHub ↗

Related Claude Code Commands

Catalog data and component content are sourced from the open-source davila7/claude-code-templates project (MIT license). ToolZip curates the listing and writes original descriptions; every component links back to its original source. Claude Code is a product of Anthropic. ToolZip is an independent catalog and is not affiliated with or endorsed by Anthropic.