Environment variables in CI/CD workflows

Published on

You can use either Vite or Laravel Mix to inject environment variables from your .env file into your JavaScript bundle. If you build your application in a CI/CD pipeline like GitHub Actions, then you need to set the variables before you run npm run production or npm run build.

This post uses Laravel Mix as an example, but Vite works essentially the same way.

Environment variables

Laravel has these conventions for making variables available in your JavaScript bundle:

  • All variables defined in the shell environment
  • Variables defined in your .env file that start with MIX_ (when using Laravel Mix)
  • Variables defined in your .env file that start with VITE_ (when using Vite)

Variables defined in your environment take precedence over variables from your .env file. For example, if you run this in your terminal:

MIX_PUSHER_APP_KEY="FROM_BASH"

VITE_PUSHER_APP_KEY="FROM_BASH"

And your .env file contains:

MIX_PUSHER_APP_KEY="FROM_DOT_ENV"

VITE_PUSHER_APP_KEY="FROM_DOT_ENV"

Then this is the result in your JavaScript bundle:

process.env.MIX_PUSHER_APP_KEY === "FROM_BASH"

import.meta.env.VITE_PUSHER_APP_KEY === "FROM_BASH"

Using variables in a GitHub Actions workflow

In a GitHub workflow you can set environment variables using the env key. Any variable defined will be available in your JavaScript bundle via the process.env (Mix) or import.meta.env (Vite) object.

- name: Build JavaScript bundle
  run: |
    npm ci
    npm run production
  env:
    MIX_PUSHER_APP_KEY: "a13bb07667096c3f82"
    MIX_PUSHER_APP_CLUSTER: "eu"

Using variables in a GitLab CI/CD pipeline

In a GitLab CI/CD pipeline you can define environment variables using the variables key, followed by an object. Any variable defined like this will be available in your JavaScript bundle via the process.env object.

build-javascript-bundle:
    variables: {
      MIX_PUSHER_APP_KEY: "a13bb07667096c3f82",
      MIX_PUSHER_APP_CLUSTER: "eu",
    }
    script:
      - npm ci
      - npm run production

Using variables in a Bitbucket Pipeline

Bitbucket Pipelines don't have a special key for defining environment variables, so we have to use bash instead:

- step: &build_javascript_bundle
      name: Build JavaScript Bundle
      image: atlassian/default-image:4
      script:
          - MIX_PUSHER_APP_KEY="a13bb07667096c3f82"
          - MIX_PUSHER_APP_CLUSTER="eu"
          - npm ci
          - npm run production

Using defaults from your .env.example

You can also define default values in your .env.example file. You can use these defaults in your workflow by turning the example file into the real .env file:

- name: Build JavaScript bundle
  run: |
    cp .env.example .env
    npm ci
    npm run production
  env:
    MIX_PUSHER_APP_KEY: "this value takes precedence"

Remember that any value defined in the shell environment will override what is in your .env file.

Multiple environments

If you deploy multiple environments with the same workflow, they might need different variables. The GitHub Actions example below shows how to build your bundle for two different branches.

- name: Build JavaScript bundle for production
  if: github.ref == 'refs/heads/main'
  run: |
    npm ci
    npm run production
  env:
    MIX_PUSHER_APP_KEY: "a13bb07667096c3f82"
    MIX_PUSHER_APP_CLUSTER: "eu"

- name: Build JavaScript bundle for staging
  if: github.ref == 'refs/heads/develop'
  run: |
    npm ci
    npm run production
  env:
    MIX_PUSHER_APP_KEY: "c611e00e2ab864a1ef"
    MIX_PUSHER_APP_CLUSTER: "us"

Variables in your Javascript bundle aren't secrets

Remember that any variables that are included in your javascript bundle aren't secret. Values like MIX_PUSHER_APP_KEY are sent in included in your bundle and sent to the front-end. I generally recommend just putting these variables in plain text in your workflow file, this is more convenient than handling them like real secrets.