Rails credentials have been around since 5.2, but I still see apps with API keys in plain .env files, so consider this the updated version of my old secrets-to-credentials post - how it works in Rails 8.

The idea

Your app has two files that come as a pair:

  • config/master.key - git-ignored, never committed;
  • config/credentials.yml.enc - encrypted with that key, safe to commit.

The encrypted file holds your API keys, tokens and so on, and because it’s in version control, every branch and every teammate has the same structure - they just need the key.

Editing

EDITOR="code --wait" bin/rails credentials:edit

Swap code for whatever editor you use. The decrypted YAML opens up, you edit, save, close, and Rails re-encrypts it. Structure it however you like:

aws:
  access_key_id: 123
  secret_access_key: 345
api_keys:
  google:
    maps: 'DEF'

Reading values

The dig style is the one to use, since it returns nil rather than blowing up when a key is missing:

Rails.application.credentials.dig(:aws, :access_key_id)
Rails.application.credentials.dig(:api_keys, :google, :maps)

Per-environment credentials

This is the bit my original post predates. You can have a separate encrypted file per environment:

bin/rails credentials:edit --environment production

That creates config/credentials/production.yml.enc with its own production.key, so your production secrets never even exist on a development machine.

In production

Set the key as an environment variable on your server:

RAILS_MASTER_KEY=xxxxxxxxxxxxxxxxx

If you’re deploying with Kamal (the Rails 8 default), it reads that from .kamal/secrets and passes it along. And add this to config/environments/production.rb so the app fails loudly if the key is missing rather than limping along:

config.require_master_key = true

That’s it - you’re all set. Welcome to not having a .env file to lose.