Skip to content
⚠️ This article was written in 2018. Some content may be outdated.

Frontend Engineering: Multi-Environment Configuration Management

Projects typically have development, staging, and production environments with different API endpoints, feature flags, and other configurations. This post covers best practices for multi-environment config management.

Environment Variables Basics

Vue CLI 3 has built-in dotenv support and reads .env.* files:

.env                  loaded in all environments
.env.local            all environments, but not committed to git (for local overrides)
.env.development      development environment
.env.staging          staging environment (custom)
.env.production       production environment
bash
# .env.development
VUE_APP_API_BASE=http://localhost:3000
VUE_APP_ENV=development
VUE_APP_DEBUG=true

# .env.staging
VUE_APP_API_BASE=https://api.staging.example.com
VUE_APP_ENV=staging
VUE_APP_DEBUG=false

# .env.production
VUE_APP_API_BASE=https://api.example.com
VUE_APP_ENV=production
VUE_APP_DEBUG=false

Note: only variables prefixed with VUE_APP_ are injected into client-side code.

javascript
// Using in code
const apiBase = process.env.VUE_APP_API_BASE;
const isDebug = process.env.VUE_APP_DEBUG === "true";

Running a Specific Environment

json
{
  "scripts": {
    "serve": "vue-cli-service serve",
    "serve:staging": "vue-cli-service serve --mode staging",
    "build": "vue-cli-service build",
    "build:staging": "vue-cli-service build --mode staging",
    "build:production": "vue-cli-service build --mode production"
  }
}

Multi-Environment Config Structure

javascript
// src/config/index.js
const envConfigs = {
  development: {
    apiBase: process.env.VUE_APP_API_BASE,
    uploadUrl: "http://localhost:3000/upload",
    wsUrl: "ws://localhost:3001",
    features: {
      debugPanel: true,
      mockData: true,
    },
  },
  staging: {
    apiBase: process.env.VUE_APP_API_BASE,
    uploadUrl: "https://upload.staging.example.com",
    wsUrl: "wss://ws.staging.example.com",
    features: {
      debugPanel: true,
      mockData: false,
    },
  },
  production: {
    apiBase: process.env.VUE_APP_API_BASE,
    uploadUrl: "https://upload.example.com",
    wsUrl: "wss://ws.example.com",
    features: {
      debugPanel: false,
      mockData: false,
    },
  },
};

const env = process.env.VUE_APP_ENV || "development";
export default envConfigs[env];
javascript
// Usage
import config from "@/config";

axios.defaults.baseURL = config.apiBase;

if (config.features.debugPanel) {
  // show debug panel
}

Handling Sensitive Information

Never put secret keys in client-side code:

bash
# ❌ Don't do this, even in .env files
VUE_APP_STRIPE_SECRET_KEY=sk_live_xxxxx  # will be bundled into JS!
VUE_APP_DB_PASSWORD=xxxxx

# ✅ Only put public config
VUE_APP_STRIPE_PUBLIC_KEY=pk_live_xxxxx  # publishable keys can be public
VUE_APP_API_BASE=https://api.example.com

Secrets (API secrets, database passwords) belong only in server-side environment variables.

Git Management of .env Files

ini
# .gitignore
.env.local
.env.*.local

# These can be committed (without sensitive info):
# .env
# .env.development
# .env.staging
# .env.production

Provide a sample file so new team members know what variables are needed:

bash
# .env.example (committed to git)
VUE_APP_API_BASE=          # fill in your API base URL
VUE_APP_ENV=development
VUE_APP_SENTRY_DSN=        # optional: Sentry DSN

Build-time Configuration Differences

Some config is only needed for specific environment builds:

javascript
// vue.config.js
const isProduction = process.env.NODE_ENV === "production";

module.exports = {
  productionSourceMap: false, // don't generate source maps in production (security)

  chainWebpack: (config) => {
    if (isProduction) {
      // upload source maps to Sentry in production
      config.plugin("sentry").use(SentryWebpackPlugin, [
        {
          release: process.env.APP_VERSION,
        },
      ]);
    }
  },

  configureWebpack: {
    // use CDN externals in production
    externals: isProduction
      ? {
          vue: "Vue",
          "element-ui": "ELEMENT",
        }
      : {},
  },
};

Environment Variables in CI/CD

Configure sensitive variables on the CI/CD platform (GitLab CI, Jenkins):

yaml
# .gitlab-ci.yml
build_staging:
  stage: build
  script:
    - npm ci
    - npm run build:staging
  variables:
    VUE_APP_SENTRY_DSN: $STAGING_SENTRY_DSN # references a CI platform secret
  environment:
    name: staging

MIT Licensed