Vercel Env Sync
Synchronize environment variables between local development and Vercel deployments
Before you use this component
This is a third-party source bundle, not an installation into your account. UI Discovery has checked the available redistribution license evidence; runtime behavior has not been tested. Review all files, use a disposable project first, and do not enable scripts or hooks until you understand their permissions.
Some integrations require separately installed software, API keys or paid services. Credentials and subscriptions are not included. These are Claude Code resources; other clients may require adaptation.
Extract the ZIP into a temporary folder, inspect its entry file and supporting resources, then follow the original instructions. Do not overwrite an existing project configuration blindly. Keep the bundled license and attribution notices.
- Source publisher
- Claude Code Templates
- Creator supplied by source
- Not listed in source
- Pinned source version
- a344359459263d73d8948651c789244093c02e4e
- License evidence
- LICENSE
Source preview
cli-tool/components/commands/nextjs-vercel/vercel-env-sync.md
---
allowed-tools: Read, Write, Edit, Bash
argument-hint: [--pull] [--push] [--validate] [--backup]
description: Synchronize environment variables between local development and Vercel deployments
---
## 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
```typescript
// 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
```bash
# 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
```bash
#!/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
```bash
#!/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
```typescript
// 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
```bash
#!/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
```typescript
// 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<string, string>) {
const categories: Record<string, Array<{
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 getDatabaseDescription(key: string): string {
if (key === 'DATABASE_URL') return 'Database connection string';
if (key === 'DB_HOST') return 'Database host';
if (key === 'DB_PORT') return 'Database port';
if (key === 'DB_NAME') return 'Database name';
return 'Database configuration';
}
function getAuthDescription(key: string): string {
if (key === 'NEXTAUTH_SECRET') return 'NextAuth.js secret key';
if (key === 'NEXTAUTH_URL') return 'NextAuth.js canonical URL';
if (key === 'JWT_SECRET') return 'JWT secret key';
return 'Authentication configuration';
}
function getApiDescription(key: string): string {
return `API key for ${key.toLowerCase().replace(/_/g, ' ')}`;
}
function getConfigDescription(key: string): string {
return `Configuration for ${key.toLowerCase().replace(/_/g, ' ')}`;
}
```
### 3. Security and Validation
```bash
#!/bin/bash
# Security checks for environment variables
security_check() {
echo "🔐 Running security checks on environment variables..."
local issues=0
# Check for common security issues
for file in .env.local .env.development .env.staging .env.production; do
if [ ! -f "$file" ]; then
continue
fi
echo "🔍 Checking $file..."
# Check for weak secrets
while IFS='=' read -r key value; do
if [[ -z "$key" || "$key" =~ ^#.* ]]; then
continue
fi
# Remove quotes
value=$(echo "$value" | sed 's/^"\(.*\)"$/\1/' | sed "s/^'\(.*\)'$/\1/")
# Check for placeholder values
if [[ "$value" == *"your-"* || "$value" == *"change-me"* || "$value" == *"replace-me"* ]]; then
echo "⚠️ Placeholder value in $key"
((issues++))
fi
# Check for short secrets
if [[ "$key" =~ (SECRET|PRIVATE|KEY|TOKEN) ]]; then
if [ ${#value} -lt 16 ]; then
echo "⚠️ $key appears to be too short for a secret (${#value} characters)"
((issues++))
fi
fi
# Check for hardcoded URLs in production
if [[ "$file" == *"production"* && "$value" =~ localhost ]]; then
echo "⚠️ $key contains localhost in production environment"
((issues++))
fi
done < "$file"
done
# Check if .env files are in .gitignore
if [ -f .gitignore ]; then
if ! grep -q ".env.local" .gitignore; then
echo "⚠️ .env.local not in .gitignore"
((issues++))
fi
if ! grep -q ".env.production" .gitignore; then
echo "⚠️ .env.production not in .gitignore"
((issues++))
fi
else
echo "⚠️ No .gitignore file found"
((issues++))
fi
echo ""
if [ $issues -eq 0 ]; then
echo "✅ No security issues found"
else
echo "❌ Found $issues security issues"
exit 1
fi
}
security_check
```
## Automation and Integration
### 1. GitHub Actions Integration
```yaml
# .github/workflows/env-sync.yml
name: Environment Sync
on:
push:
branches: [main, develop]
paths: ['.env.example', '.env.*']
workflow_dispatch:
inputs:
action:
description: 'Sync action'
required: true
default: 'validate'
type: choice
options:
- validate
- pull
- push
jobs:
env-sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Vercel CLI
run: npm i -g vercel@latest
- name: Link to Vercel
run: vercel link --token=${{ secrets.VERCEL_TOKEN }} --yes
- name: Validate Environment
if: github.event.inputs.action == 'validate' || github.event.inputs.action == ''
run: |
# Run environment validation
node scripts/validate-env.js
- name: Pull Environment
if: github.event.inputs.action == 'pull'
run: |
vercel env pull .env.ci --token=${{ secrets.VERCEL_TOKEN }}
# Validate pulled environment
node scripts/validate-env.js .env.ci
- name: Push Environment
if: github.event.inputs.action == 'push'
run: |
# Push environment variables to Vercel
node scripts/push-env.js --token=${{ secrets.VERCEL_TOKEN }}
```
### 2. Development Workflow Integration
```bash
#!/bin/bash
# Pre-commit hook for environment validation
echo "🔍 Validating environment variables..."
# Check if environment files are properly configured
if [ -f .env.local ]; then
echo "✅ .env.local exists"
else
echo "⚠️ .env.local not found"
if [ -f .env.example ]; then
echo "💡 Copy .env.example to .env.local and configure your variables"
fi
fi
# Validate environment structure
node scripts/validate-env.js
if [ $? -ne 0 ]; then
echo "❌ Environment validation failed"
exit 1
fi
echo "✅ Environment validation passed"
```
## Comprehensive Sync Operations
Implement complete environment synchronization workflow with validation, backup, security checks, and automation integration for seamless development and deployment processes.
<function_calls>
<invoke name="TodoWrite">
<parameter name="todos">[{"content": "Analyze hook system and context monitoring capabilities", "status": "completed"}, {"content": "Design context threshold detection mechanism", "status": "completed"}, {"content": "Create hook script for automatic compact + clear sequence", "status": "pending"}, {"content": "Configure hook in settings.json with proper event triggers", "status": "pending"}, {"content": "Test hook execution and threshold detection", "status": "pending"}, {"content": "Add markdown copy button to Supabase blog post", "status": "completed"}, {"content": "Write Claude Code + Next.js and Vercel Integration article", "status": "completed"}, {"content": "Create Next.js Architecture Expert agent", "status": "completed"}, {"content": "Create Vercel Deployment Specialist agent", "status": "completed"}, {"content": "Create React Performance Optimizer agent", "status": "completed"}, {"content": "Create Next.js app scaffolding command", "status": "completed"}, {"content": "Create Vercel deployment optimization command", "status": "completed"}, {"content": "Create component generator command", "status": "completed"}, {"content": "Create API route tester command", "status": "completed"}, {"content": "Create bundle analyzer command", "status": "completed"}, {"content": "Create middleware creator command", "status": "completed"}, {"content": "Create edge function generator command", "status": "completed"}, {"content": "Create performance audit command", "status": "completed"}, {"content": "Create environment sync command", "status": "completed"}, {"content": "Create migration helper command", "status": "in_progress"}]Preview capped at 60,000 characters. Download the bundle for every original file and notice.
Read the redistribution license
MIT License Copyright (c) 2025 Daniel (San) Ávila Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Bundle SHA-256: a52aea87adf7b4bf0c2111456f1980b9c4091089690e524566aa6937aa80dc7f. Files are served as downloads and are never executed by this page.