Skip to main content

Environment Variables with dotenv-rails

dotenv-rails loads environment variables from .env files into ENV when your app boots. It's the standard way to manage local config values or manually exporting variables in your shell.

Install​

Add this line to the application's Gemfile and run bundle install:

# Gemfile
gem "dotenv-rails", groups: [:development, :test]
bundle install

That's all the setup needed. dotenv-rails loads automatically when your Rails app boots, before any initializers run.

Create a .env File​

Create a .env file in your project root:

# .env
DATABASE_URL=postgres://localhost/myapp_development
PAYMENT_API_KEY=test_abc123
LOG_LEVEL=debug

Variables are available in your app via ENV:

ENV["DATABASE_URL"]              # => "postgres://localhost/myapp_development"
ENV.fetch("PAYMENT_API_KEY") # => "test_abc123"

File Loading Priority​

dotenv-rails loads multiple files depending on the current RAILS_ENV. The order from highest to lowest priority:

.env.development.local
.env.local
.env.development
.env

The first file that defines a variable wins. So .env.development.local overrides everything, and .env is the base fallback.

Here's what each file is for:

.env — base config shared across all environments .env.development — development-specific values .env.local — personal overrides, not scoped to any environment .env.development.local — personal overrides scoped to development only

In practice, most projects only need .env and .env.local.

.gitignore​

Always add your local override files to .gitignore:

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

Whether to commit .env itself depends on what's in it. If it only contains non-sensitive defaults (localhost URLs, dev-mode feature flags), committing it makes onboarding easier for other developers.

.env.example as a Template​

A common pattern is to commit a .env.example with all the required keys but no real values. New team members copy it and fill in their own values:

# .env.example
DATABASE_URL=
REDIS_URL=
PAYMENT_API_KEY=
LOG_LEVEL=debug
cp .env.example .env.local

dotenv-rails in Test​

Since v3.0, dotenv-rails automatically restores ENV after each test. This means you can modify ENV in a test without worrying about leaking state to other tests. It works with both Minitest and RSpec out of the box.

To disable it:

config/environments/test.rb
config.dotenv.autorestore = false

Production​

Use platform's native secret management: GCP Secret Manager, AWS Secrets Manager, Kubernetes secrets, etc.

References​