# Rails environment variables vs credentials.yml.enc

> Rails keeps secrets in encrypted credentials opened by a master key, and lets ENV override some of them. When to use which, and how to run Rails with Crunu.

URL: https://crunu.com/environment-variables/rails
Language: en
Updated: 2026-10-30

Rails reads environment variables through Ruby's `ENV`, which holds whatever the process was started with. Rails 8.1 doesn't load a `.env` file on its own. For secrets, Rails has its own store: encrypted credentials in `config/credentials.yml.enc`, or `config/credentials/production.yml.enc` per environment, opened with a master key from `config/master.key` or the `RAILS_MASTER_KEY` variable. A few settings check `ENV` first and credentials second, most importantly `secret_key_base`. All of it is read when the app boots, so new values need a restart. This page follows the [Rails security guide](https://guides.rubyonrails.org/security.html) and the [Rails 8.1 API](https://api.rubyonrails.org/v8.1/classes/Rails/Application.html), checked October 30, 2026, with Rails 8.1.4 current.

## Two sources, and which one wins

| Value             | Looked up in                                                        | Notes                                                                     |
| ----------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `secret_key_base` | 1. `ENV["SECRET_KEY_BASE"]` 2. credentials                          | in development and test, generated into `tmp/local_secret.txt` if missing |
| credentials key   | 1. `ENV["RAILS_MASTER_KEY"]` 2. key file                            | `config/credentials/ENV.key`, else `config/master.key`                    |
| credentials file  | 1. `config/credentials/ENV.yml.enc` 2. `config/credentials.yml.enc` | `ENV` here means the Rails environment name                               |
| your own settings | wherever your code reads them                                       | `ENV.fetch` or `Rails.application.credentials`                            |

*Figure: Diagram of how Ruby on Rails loads environment variables. No env files are read by default; values come from the environment of the process. Values are read from the environment when the app starts. There is no public prefix: nothing reaches the browser unless your code sends it.*

There is no file chain like `.env.local` over `.env`. If you want one, a gem has to provide it. Everything else is a decision your code makes, one setting at a time.

## How credentials work

`bin/rails credentials:edit` decrypts the credentials file into your editor and encrypts it again when you close it. It creates the file and a master key if neither exists. Add `--environment production` to edit the production file, which gets its own key. The encrypted file is meant to be committed: the guide says it can be stored in version control as long as the master key is kept safe, and it says in so many words not to commit the master key.

Code reads values through `Rails.application.credentials`, for example `Rails.application.credentials.stripe_secret_key`, or a nested path like `credentials.aws.access_key_id`. The bang form, `stripe_secret_key!`, raises `KeyError` when the value is blank, which is the safer choice for anything required.

By default the credentials file contains `secret_key_base`, the input for the key generator behind every message verifier and encryptor in the app, including signed and encrypted cookies. Generate a new value with `bin/rails secret`.

## What changing secret_key_base breaks

The guide spells it out: changing `secret_key_base` expires all active sessions and requires every user to log in again, and encrypted or signed cookies and Active Storage files can be affected too. Two consequences follow:

- **An environment variable can change it by accident.** `ENV["SECRET_KEY_BASE"]` beats the credentials value. A variable left over in a server's environment, a container platform's settings or a CI job quietly replaces the key in credentials, and the symptom is that everyone is logged out after a deploy.
- **Builds don't need the real key.** `rails assets:precompile` boots the app, so it needs some `secret_key_base`. Rails documents `SECRET_KEY_BASE_DUMMY=1` for exactly this case, for example in a Dockerfile, which generates a random throwaway key for the build. The real key then only exists where the app runs.

## Credentials or environment variables?

Both are reasonable, and the trade-offs are about people more than about Ruby:

|                            | Encrypted credentials                      | Environment variables        |
| -------------------------- | ------------------------------------------ | ---------------------------- |
| Where values live          | in the repository, encrypted               | outside the repository       |
| What a server needs        | one key per Rails environment              | every value                  |
| Changing one value         | edit, commit, deploy                       | change the variable, restart |
| Removing a person's access | new master key, re-encrypt, reissue values | depends on the store you use |
| Old versions               | stay in Git history                        | depend on the store          |

The fourth and fifth rows are the ones teams underestimate. A master key opens every version of the file that was ever committed with it. When someone who had the production key leaves, generating a new key protects only future versions. Every value they could read is still readable from history and has to be reissued at its provider.

## Before you change anything, take stock

A Rails app that has been around for a while usually reads secrets from three places at once: credentials, `ENV` lookups added later, and gem defaults that read their own variables. Moving any of it is easier after a short inventory:

- **List every key in each credentials file**, by name only. Note which ones code still reads. Unused keys are values you'd otherwise keep reissuing for nothing.
- **Search the code for `ENV[` and `ENV.fetch`.** Each hit is a variable some server must provide. Compare the list with what your hosts actually set.
- **Check every place that can set `SECRET_KEY_BASE`.** Server environments, container settings and CI jobs. If one sets it, that value wins over credentials, and you want to know before a deploy changes it.
- **Find out who holds each master key.** Laptops, CI variables, password managers, the old deploy server. That list is your offboarding scope for credentials.

The result tells you which values belong in credentials, which in the environment, and which can simply be deleted.

## Run Rails with values from Crunu

`crunu run` starts your command with the variables of a Crunu environment in its process environment, so Rails sees them in `ENV`. There are two ways to combine that with credentials.

**Keep credentials, move only the key.** Store `RAILS_MASTER_KEY` for each Rails environment in the matching Crunu environment. The server never has a key file on disk, and Crunu controls who can read the key. Everything about credentials stays the same, including the offboarding caveat above.

**Move the values themselves.** Read secrets with `ENV.fetch("STRIPE_SECRET_KEY")` in initializers or in `config/environments/production.rb`, and keep them in Crunu. Each environment keeps its own version history, access is granted per environment, and when someone leaves, Crunu's offboarding report shows which versions of which environments they received and lists the values to reissue.

1. Put `RAILS_ENV` and either `RAILS_MASTER_KEY` or the individual secrets into Crunu environments such as `rails-app/development` and `rails-app/production`.
2. Develop with `crunu run --env rails-app/development -- bin/rails server` after a one-time `crunu login`.
3. Build images with `SECRET_KEY_BASE_DUMMY=1` for asset precompilation, so no real secret is needed during the build.
4. On a Linux server with the agent, start Puma with `crunu run --env rails-app/production --restart on-change -- bundle exec puma -C config/puma.rb`.

`RAILS_ENV` belongs in the environment because `crunu run` passes only a short allowlist from your shell, such as `PATH` and `HOME`. `PATH` keeps rbenv or asdf shims working. Variables like `BUNDLE_GEMFILE` or `SSH_AUTH_SOCK`, which Bundler may need for private Git gems, are not passed, so add them or use `--inherit-env` for that command.

With `--restart on-change`, `crunu` restarts Puma after a value changes, which is how a new database password or API key reaches the app. Don't let it rotate `SECRET_KEY_BASE` casually: the restart applies the new key, and every user is signed out.

## Related reading

- [Laravel](https://crunu.com/environment-variables/laravel) has encrypted `.env` files with a similar trade-off.
- [Django](https://crunu.com/environment-variables/django) for a key with built-in fallbacks.
- [Generate a Rails secret_key_base](https://crunu.com/tools/secret-generator/rails-secret-key-base) in your browser.
- [Developer offboarding: which secrets to rotate](https://crunu.com/guides/developer-offboarding-secret-rotation) and [how to share .env files with your team](https://crunu.com/guides/share-env-files-with-a-team).

## FAQ

### Should I use Rails credentials or environment variables?

Credentials keep encrypted values in the repository and need only one key per environment on the server. Environment variables keep values out of the repository entirely and let each value change on its own. Many apps combine them: credentials for most values, ENV for what differs per deployment.

### Where should RAILS_MASTER_KEY live?

Anywhere except the repository. The Rails guide says not to commit the master key. On servers, pass it as the RAILS_MASTER_KEY environment variable, for example from Crunu, or as the key file with restricted permissions.

### Do per-environment credentials need their own key?

Yes. config/credentials/production.yml.enc is opened with config/credentials/production.key or RAILS_MASTER_KEY. Rails falls back to credentials.yml.enc and master.key only when the environment file doesn't exist.

### How do I generate a new secret_key_base?

Run bin/rails secret. Changing the key expires sessions, so plan the switch.

## Sources

- [Rails Guides: Securing Rails applications](https://guides.rubyonrails.org/security.html) (accessed 2026-10-30)
- [Rails 8.1 API: Rails::Application](https://api.rubyonrails.org/v8.1/classes/Rails/Application.html) (accessed 2026-10-30)
