Jekyll Environment Variables: The Complete Guide
How to use environment variables in Jekyll — JEKYLL_ENV, accessing env vars in config, conditional builds, and best practices for managing secrets.
Environment variables in Jekyll are simpler than you might expect — but also more limited than many developers assume coming from Node.js or Python. Here is everything you need to know.
JEKYLL_ENV: the key environment variable
Jekyll ships with one built-in environment variable: JEKYLL_ENV. It defaults to development when you run jekyll serve or jekyll build locally. To set it to production, prefix your build command:
JEKYLL_ENV=production jekyll build
On Netlify, Cloudflare Pages, and most CI platforms, this is set automatically.
Using JEKYLL_ENV in Liquid templates
You can read the environment in your templates using jekyll.environment:
{% if jekyll.environment == "production" %}
{% include analytics.html %}
{% endif %}
This is the standard pattern for including analytics, chat widgets, and other scripts only in production builds — keeping your development output clean and your test data separate from real analytics.
Common production-only includes
{% comment %} In _layouts/default.html {% endcomment %}
{% if jekyll.environment == "production" %}
{% include analytics.html %}
{% include cookie-banner.html %}
{% endif %}
Can Jekyll read system environment variables?
Yes — but only through _config.yml using ERB interpolation, and only when Jekyll is run with the --config flag pointing to a .yml file processed as ERB. This is not supported out of the box in standard Jekyll.
The most reliable approach for secrets in Jekyll is to use your hosting platform’s environment variable system and inject values at build time.
Injecting environment variables via _config.yml on Netlify
Netlify lets you set environment variables in your site dashboard (Site settings → Environment variables). You can then reference them in netlify.toml:
[build]
command = "JEKYLL_ENV=production jekyll build"
publish = "_site"
[build.environment]
JEKYLL_ENV = "production"
For values you want available in your Liquid templates, the cleanest approach is to set them in _config.yml directly — keeping non-secret config in version control and only truly secret values (API keys, tokens) in the platform’s environment variable system.
Environment-specific config files
Jekyll supports multiple config files merged at build time. This is the recommended pattern for environment-specific settings:
# Development (default)
jekyll serve
# Production
jekyll build --config _config.yml,_config.production.yml
# Staging
jekyll build --config _config.yml,_config.staging.yml
Your _config.production.yml overrides only the values that differ:
# _config.production.yml
url: "https://yourdomain.com"
google_analytics: "G-XXXXXXXXXX"
show_drafts: false
Your _config.yml keeps safe defaults:
# _config.yml
url: "http://localhost:4000"
google_analytics: ""
show_drafts: true
Practical examples
Analytics only in production
{% comment %} _includes/analytics.html {% endcomment %}
{% if jekyll.environment == "production" and site.google_analytics != "" %}
<script async src="https://www.googletagmanager.com/gtag/js?id={{ site.google_analytics }}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag("js", new Date());
gtag("config", "{{ site.google_analytics }}");
</script>
{% endif %}
Draft posts visible in development only
# _config.yml
show_drafts: false
# _config.development.yml
show_drafts: true
jekyll serve --config _config.yml,_config.development.yml --drafts
Different base URLs per environment
# _config.yml
url: "https://jekyllhub.com"
baseurl: ""
# _config.staging.yml
url: "https://staging.jekyllhub.com"
baseurl: "/staging"
Banner or maintenance mode
# _config.yml
maintenance_mode: false
{% if site.maintenance_mode %}
<div class="maintenance-banner">We are performing maintenance. Back shortly.</div>
{% endif %}
What you cannot do directly
Jekyll does not have a .env file loader like Node.js projects. You cannot write:
# This does NOT work in Jekyll
API_KEY=abc123
…and then access `` in a template. Jekyll does not read shell environment variables into the Liquid context.
If you need to expose an API key to client-side JavaScript, remember that anything in your built _site folder is public. Never embed secret API keys in static HTML. Use a proxy function (Netlify Functions, Cloudflare Workers) to make authenticated requests from the server side.
Summary
| Pattern | Use case |
|---|---|
JEKYLL_ENV=production |
Toggle analytics, ads, and scripts |
Multiple _config files |
Environment-specific URLs and settings |
Platform env vars in netlify.toml |
Inject build-time values |
jekyll.environment in Liquid |
Conditional template logic |
Keep your environment strategy simple. For most Jekyll sites, JEKYLL_ENV plus a production config override covers everything you need.