Gatsby Environment Variables — Managing Configuration Across Environments
Learn how to use environment variables in Gatsby for API keys, configuration, and environment-specific settings across development and production.
In this lesson, you'll understand how Gatsby handles environment variables, how to create .env files, and how to access variables in different contexts.
What You'll Learn
How to create .env.development and .env.production files, access variables in Node.js and browser code, and use variables in gatsby-config.js.
Why It Matters
Environment variables keep secrets out of your codebase. They let you use different API endpoints, analytics IDs, and feature flags across environments.
flowchart LR
A[.env.development] --> B[gatsby-config.js]
A --> C[Client Code]
D[.env.production] --> B
D --> C
B --> E[API Endpoints]
C --> F[Feature Flags]
style B fill:#639,color:#fff
Setting Up Environment Variables
# .env.development
GATSBY_API_URL=http://localhost:3000/api
GATSBY_ANALYTICS_ID=UA-DEV-XXXXX
CONTENTFUL_SPACE_ID=dev_space
CONTENTFUL_ACCESS_TOKEN=dev_token
ENABLE_EXPERIMENTAL_FEATURE=true
# .env.production
GATSBY_API_URL=https://api.example.com
GATSBY_ANALYTICS_ID=UA-PROD-XXXXX
CONTENTFUL_SPACE_ID=prod_space
CONTENTFUL_ACCESS_TOKEN=prod_token
ENABLE_EXPERIMENTAL_FEATURE=false
Variables prefixed with GATSBY_ are available in browser code. Variables without the prefix are only available in Node.js (gatsby-config.js, gatsby-node.js).
Using Variables in gatsby-config.js
// gatsby-config.js
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`
});
module.exports = {
siteMetadata: {
siteUrl: process.env.GATSBY_SITE_URL || 'http://localhost:8000'
},
plugins: [
{
resolve: 'gatsby-source-contentful',
options: {
spaceId: process.env.CONTENTFUL_SPACE_ID,
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN
}
},
{
resolve: 'gatsby-plugin-google-analytics',
options: {
trackingId: process.env.GATSBY_ANALYTICS_ID
}
}
]
};
Output: The Contentful and Analytics plugins use environment-specific credentials without hardcoding secrets.
Using Variables in Client Code
Access GATSBY_ prefixed variables anywhere:
// src/components/APIStatus.js
import React, { useState, useEffect } from 'react';
export default function APIStatus() {
const [status, setStatus] = useState('checking');
useEffect(() => {
fetch(`${process.env.GATSBY_API_URL}/health`)
.then(res => res.json())
.then(data => setStatus(data.status))
.catch(() => setStatus('offline'));
}, []);
return <p>API Status: {status}</p>;
}
Output: The component fetches from the development API in dev mode and the production API in production.
Using Variables in gatsby-node.js
// gatsby-node.js
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`
});
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions;
// Use environment variable for feature flag
const enableBeta = process.env.ENABLE_BETA_FEATURES === 'true';
if (enableBeta) {
// Create beta-only pages
createPage({
path: '/beta/',
component: path.resolve('./src/templates/beta.js')
});
}
};
Output: Beta pages are only created when ENABLE_BETA_FEATURES=true in the environment.
Adding Environment Variables to CI/CD
# .github/workflows/deploy.yml
name: Deploy
on: [push]
jobs:
build:
runs-on: ubuntu-latest
env:
CONTENTFUL_SPACE_ID: ${{ secrets.CONTENTFUL_SPACE_ID }}
CONTENTFUL_ACCESS_TOKEN: ${{ secrets.CONTENTFUL_ACCESS_TOKEN }}
GATSBY_API_URL: ${{ secrets.API_URL }}
GATSBY_ANALYTICS_ID: ${{ secrets.ANALYTICS_ID }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci
- run: npm run build
- run: npm run deploy
Output: Secrets are stored in GitHub Secrets and injected as environment variables during CI/CD builds.
Common Mistakes
- Committing
.envfiles: Add.env*to.gitignore. Use.env.exampleas a template for required variables. - Using non-GATSBY_ prefix in client code: Only variables prefixed with
GATSBY_are available in browser JavaScript. Other variables areundefined. - Not loading dotenv in Node.js files:
gatsby-config.jsandgatsby-node.jsneedrequire('dotenv').config()to load.envfiles. - Hardcoding fallback secrets: Never put real secrets as default values:
Process.env.SECRET || 'fallback_secret'. - Missing
.env.productionin CI: CI/CD pipelines need the production.envfile configured via secrets or environment variables.
Practice Questions
What prefix makes environment variables available in browser code? Answer:
GATSBY_. Variables likeGATSBY_API_URLare available in client code viaprocess.env.GATSBY_API_URL.How do you load environment variables in
gatsby-config.js? Answer: Addrequire('dotenv').config({ path:.env.${process.env.NODE_ENV}})at the top.What is the purpose of
.env.example? Answer: It documents which environment variables are required without exposing real values. Developers copy it to create their own.envfiles.How do you use different API URLs in dev and production? Answer: Set
GATSBY_API_URLin both.env.developmentand.env.productionwith different values. The correct one is loaded based onNODE_ENV.
Challenge
Create a feature flag system using environment variables: ENABLE_DARK_MODE, ENABLE_BETA_FEATURES, MAX_UPLOAD_SIZE_MB. Use them in both gatsby-node.js (to control page creation) and in components (to show/hide features).
Mini Project
Set up a multi-environment Gatsby project with: separate Contentful spaces for dev and prod, different analytics IDs per environment, feature flags for in-development features, and a CI/CD pipeline with secrets configured.
FAQ
What's Next
Learn about Gatsby Deployment to deploy your Gatsby site to production hosting platforms.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro