Migrating from Secrets to Credentials
You may not be aware that, since Rails 7.1, the standard way to store secrets is by using credentials.yml instead of the old secrets.yml.
DEPRECATION WARNING:
`Rails.application.secrets` is deprecated in favor of `Rails.application.credentials`
and will be removed in Rails 7.2.
If you still see this warning, your app uses secrets.yml and the migration applies to you. If you don’t use Rails.application.secrets or config/secrets.yml at all, you can ignore the deprecation and the rest of this post.
The migration itself isn’t hard, but it can take some coordination: if your app runs in several environments, you’ll probably need to work with whoever manages your servers to move everything over. This post walks you through it, and explains why the change matters and what you gain from it.
The History
Rails.application.secrets, backed by the config/secrets.yml file, has been the standard way to set up since Rails 4.1 , April 2014.
Before this, secrets were dispersed across environment variables and initializers (like the typical config/initializers/secret_token.rb), so Rails 4.1 introduced config/secrets.yml to provide a single, environment specific place to store API keys, database passwords, and the secret_key_base.
In Rails 5.2 , the credentials started to be encrypted by using Rails.application.credentials, and it uses config/credentials.yml.enc (which is encrypted at rest) and a config/master.key to decrypt it, but in the meantime, secrets.yml was kept for backward compatibility.
In Rails 7.1, both Rails.application.secrets and config/secrets.yml were officially deprecated, and today the standard is to use Rails.application.credentials for encrypted secrets, or standard Environment Variables (ENV) (often managed via tools like dotenv or directly in your hosting provider’s dashboard).
The Reason
Until this change, secrets.yml was plain text, and now, after this change, you will have an encrypted config/credentials.yml.enc which can be stored in version control, as long as you don’t commit your config/master.key.
Step-by-Step Migration Guide
1. Generate the file
You can generate the new file by doing:
rails credentials:edit
This will generate the new config/credentials.yml.enc file and config/master.key.
Sometimes, you need to specify your editor for this to work. For example:
EDITOR="vim" rails credentials:edit
EDITOR="code --wait" rails credentials:edit
Note: code --wait only works if the code command is installed in your PATH. If it isn’t, open VS Code, run “Shell Command: Install ‘code’ command in PATH” from the command palette, and try again.
2. Edit the file
Running this command opens a YAML file in your editor, and it will look something like this:
# smtp:
# user_name: my-smtp-user
# password: my-smtp-password
#
# aws:
# access_key_id: 123
# secret_access_key: 345
# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
secret_key_base: your_secret_key_base_here
Copy your existing values from secrets.yml or .env into this file, then save and close.
One thing to keep in mind: secrets.yml runs ERB, but credentials don’t. So if your old file had something like:
some_secret: <%= ENV["SOME_ENV_VAR"] %>
You can’t just copy that line. Credentials are plain YAML, so the <%= ... %> ends up saved as text instead of being evaluated. You have two options:
- Use the final value, not the ERB. These values usually change per environment, so you’ll need to get the real one from each (production, staging, etc.), not just what’s in your local
.env. If that’s your case, environment-specific credentials work better than one shared file. - Keep it as a plain ENV var. Not everything has to live in credentials. If it already comes from the environment, you can leave it there.
3. Update your code
Update the calls in your code
Before:
Rails.application.secrets.aws[:access_key_id]
# or, if you were using env vars:
ENV['AWS_ACCESS_KEY_ID']
After:
Rails.application.credentials.aws[:access_key_id]
Rails.application.credentials.dig(:aws, :access_key_id)
Both read the same value. Prefer .dig when a key might be missing: it returns nil instead of raising a NoMethodError.
4. Production
For the production environment, the preferred way is to set the RAILS_MASTER_KEY environment variable with the content of your master key. Copying the key file manually to the server also works, but it’s easier to accidentally commit it or misconfigure, so use that only as a fallback.
5. Cleaning
Clean up by deleting secrets.yml and removing the specific environment variables you migrated to credentials. Before deleting, deploy and confirm the app starts cleanly in each environment.
Environment-specific credentials
By default all your secrets live in one file shared across every environment. If you want production secrets to be separate from development, you can create credentials per environment:
rails credentials:edit --environment production
This is useful when you don’t want your whole team to read production secrets, or when staging and production use different values for the same keys. Each environment gets its own file and its own key, so you can give the production key only to the people (and servers) that actually need it.
The command generates a config/credentials/production.yml.enc file, and also a separate config/credentials/production.key to decrypt it. Keep in mind this is a new key file you have to manage securely on your servers, the same way you do with config/master.key.
Conclusion and next steps
And that’s it. As you saw, moving from secrets.yml to credentials is not a big deal: you copy your values, change the calls in your code, set the master key on your servers, and delete the legacy files. The nice part is that now your secrets are encrypted, so you can keep them in git with peace of mind.
If you ask me, the best moment to do this is during a Rails upgrade, but don’t bundle it into a single version jump. secrets.yml is deprecated in 7.1 and gone in 7.2, so do the migration after you land on 7.1 and before you move to 7.2. That way you don’t mix the secrets change with the rest of the 7.2 work.
Need a hand with your Rails upgrade? We can help!