Vercel Env Sync
Synchronize environment variables between local development and Vercel deployments
$ npx claude-code-templates@latest --command="nextjs-vercel/vercel-env-sync" --yesRequires 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: $ARGUMENTSCurrent Environment Analysis
Local Environment
- Environment files:
- @.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 →
Related Claude Code Commands
Nextjs Component Generator
Generate optimized React components for Next.js with TypeScript and best practices
Nextjs Performance Audit
Comprehensive Next.js performance audit with actionable optimization recommendations
Nextjs Bundle Analyzer
Analyze and optimize Next.js bundle size with detailed recommendations
Vercel Deploy Optimize
Optimize and deploy Next.js application to Vercel with performance monitoring
Nextjs Api Tester
Test and validate Next.js API routes with comprehensive test scenarios
Nextjs Middleware Creator
Create optimized Next.js middleware with authentication, rate limiting, and routing logic
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.