How To Use Rails Credentials Securely

Learn how Rails Credentials work: encrypt secrets, secure your master key, and manage config safely in development and production.

Jean Emmanuel Cadet
By Jean Emmanuel Cadet Ruby on Rails Developer
How to Use Rails Credentials Securely

• 15 min read

Share with friends

Every Rails application depends on secrets. API keys for third-party services, database passwords, payment processor tokens, and mailer credentials all have to live somewhere. The question is where, and how, you keep them out of the hands of anyone who should not see them.

Rails Credentials answer that question. They give you a single, encrypted place to store sensitive configuration values, so you never have to hardcode a secret in your codebase or paste one into a Slack message just to get an app running locally.

This guide walks through what Rails Credentials are, how the encryption actually works, how to edit and use them safely, and how they compare to environment variables. By the end, you will know exactly how to manage secrets in a Rails application without exposing them to the world.


What Are Rails Credentials?

Rails Credentials are an encrypted key-value store built directly into the framework. Instead of scattering secrets across .env files, server dashboards, and shell profiles, Rails lets you keep them in one encrypted file that lives inside your repository.

The core idea is simple. Your secrets are encrypted and committed to version control as ciphertext, while a single master key, stored outside the repository, is the only thing capable of decrypting them. Anyone who clones your repository sees only scrambled data. Only someone with the master key can read the actual values.

This approach solves a real problem. Before Rails Credentials existed, teams often ended up with secrets pasted into config/application.yml, .env files accidentally committed to Git, or values hardcoded directly into controllers and initializers. Rails Credentials give you a structured, encrypted alternative that is versioned alongside your code, so changes to your secrets are tracked the same way changes to your application logic are.

Rails Credentials are especially useful for:

  • API keys for third-party services like Stripe, Twilio, or SendGrid
  • OAuth client IDs and secrets
  • Database connection details that should not be public
  • Mailer and SMTP credentials
  • Any application-level secret that your code needs at runtime

They are not meant to store things like feature flags or non-sensitive configuration. Those belong in regular YAML config files or environment-specific settings, not the encrypted credentials store.

Rails Credentials were introduced as the modern replacement for the older secrets.yml file, which stored values in plaintext and offered no real protection if the repository was ever exposed. The encrypted credentials system solves that gap by combining a single source of truth for secrets with strong encryption, so the file can travel with your code without becoming a liability.


How Rails Encrypted Credentials Work

Rails Credentials rely on two files working together. One holds your encrypted secrets, and the other holds the key that unlocks them.

config/credentials.yml.enc

config/credentials.yml.enc is the encrypted file that contains your actual secrets. It is safe to commit this file to your repository, including public repositories, because its contents are encrypted using AES-128-GCM. Without the correct master key, the file is unreadable.

When you open your credentials for editing, Rails decrypts the file in memory, opens it in your configured editor, lets you make changes, then re-encrypts it and writes the updated ciphertext back to disk. You never see a plaintext version of this file sitting on disk after you close your editor.

config/master.key

config/master.key is the decryption key for credentials.yml.enc. This file is generated automatically the first time you create your credentials, and it must never be committed to your repository.

By default, Rails adds config/master.key to your .gitignore file when it is generated. This is intentional and important. If this file ends up in version control, especially in a public repository, anyone with access can decrypt every secret your application has ever stored in credentials, past and present.

Think of credentials.yml.enc as a locked safe that travels with your code, and master.key as the physical key to that safe. You can hand someone the safe without any risk, but the key needs to stay with people you trust.


Editing Rails Credentials

Rails ships with built-in commands for working with credentials, so you never need to manually encrypt or decrypt anything yourself.

To open your credentials for editing:

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

Replace code --wait with whatever editor command works for your setup. VS Code, Vim, and Sublime Text with the correct wait flag all work fine. If you do not set EDITOR Rails will fall back to a default and may fail if no editor is configured.

Running this command does the following:

  1. Decrypts credentials.yml.enc using config/master.key
  2. Opens the decrypted contents in a temporary file in your editor
  3. Waits for you to save and close the file
  4. Re-encrypts the contents and writes them back to credentials.yml.enc
  5. Deletes the temporary plaintext file

If config/master.key does not exist yet, running credentials:edit for the first time will generate both master.key and credentials.yml.enc for you.

You can also view your credentials without editing them:

bin/rails credentials:show

This prints the decrypted contents to your terminal, which is useful for a quick check but should be used carefully on shared machines or in recorded terminal sessions.

Editing Credentials for a Specific Environment

Rails also supports environment-specific credentials files, which is covered in more detail later in this guide. To edit credentials for a specific environment, pass the --environment flag:

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

This creates or edits config/credentials/production.yml.enc along with a matching config/credentials/production.key, separate from your default credentials.


Storing API Keys and Service Secrets

Once you have your credentials file open, you structure it as nested YAML. Here is an example showing several common categories of secrets, using clearly fake placeholder values:

stripe:
publishable_key: pk_test_FAKEPLACEHOLDER123
secret_key: sk_test_FAKEPLACEHOLDER456

twilio:
account_sid: ACfakeaccountsid00000000000000
auth_token: fake_auth_token_placeholder

sendgrid:
api_key: SG.fake_api_key_placeholder

database:
production_password: fake_db_password_placeholder

aws:
access_key_id: FAKEACCESSKEYID
secret_access_key: fake_secret_access_key_placeholder

Nesting related secrets under a top-level key, like stripe or twilio, keeps your credentials file organized as your application grows. It also makes it easier to read and reason about which service a given secret belongs to.

You are not limited to strings. Credentials support any structure YAML supports, including arrays and deeper nesting, so you can group configuration however makes sense for your application.

A word of caution: never paste real production secrets directly into an article, a pull request description, a ticket, or a chat message, even privately. Treat every secret as if it could leak, and rotate anything that accidentally gets shared outside of the credentials file itself.


Accessing Credentials in Your Rails Application

Once secrets are stored, reading them in your application code is straightforward using Rails.application.credentials.

For a flat key:

Rails.application.credentials.dig(:sendgrid, :api_key)

For nested keys, dig is the safest approach because it returns nil instead of raising an error if a key is missing:

stripe_secret = Rails.application.credentials.dig(:stripe, :secret_key)

You can also use dot-style method access for top-level keys:

Rails.application.credentials.stripe
# => { publishable_key: "pk_test_FAKEPLACEHOLDER123", secret_key: "sk_test_FAKEPLACEHOLDER456" }

A common pattern is to wrap credential access inside a dedicated configuration object or initializer, rather than calling Rails.application.credentials throughout your codebase. This keeps your code easier to test and easier to refactor if you ever change how a secret is stored.

# config/initializers/stripe.rb
Stripe.api_key = Rails.application.credentials.dig(:stripe, :secret_key)

This pattern centralizes the credential lookup in one place, so if you later rename a key or restructure your credentials file, you only need to update one line.


Rails Credentials vs Environment Variables

Both Rails Credentials and environment variables solve the same underlying problem: keeping secrets out of your source code. They approach it differently, and each has situations where it fits better.

Rails Credentials

  • Secrets are encrypted and versioned alongside your code
  • Changes to secrets go through the same review and deployment process as code changes
  • No need to configure secrets separately on every server or hosting platform
  • Requires safely distributing the master key to anyone who needs to decrypt credentials
  • Best suited for secrets that are tightly coupled to your application and change infrequently

Environment Variables

  • Values live outside your codebase entirely, typically set by your hosting platform or process manager
  • Easy to change per deployment without touching your repository
  • Common in containerized and cloud native deployments where secrets are injected at runtime
  • No encryption built in by default, so security depends on how your platform handles them
  • Best suited for secrets that differ across deployments or that are managed by infrastructure tooling outside of Rails

When to Choose Each

Rails Credentials work well when your secrets are application-specific, and you want them versioned with your code, reviewed through pull requests, and consistent across every environment that shares the same credentials file. They shine in small to mid-sized teams where the master key can be shared securely through a password manager or secrets vault.

Environment variables work well when you are deploying to a platform that already manages secrets for you, such as a container orchestration system with its own secrets manager, or when different team members and environments genuinely need different values for the same key. They also make sense when secrets need to rotate frequently without a code deployment.

Many production Rails applications use both. Application-level secrets that rarely change might live in credentials, while infrastructure-level values like database URLs or feature flags managed by a hosting platform live in environment variables.


Environment-Specific Credentials

By default, Rails uses a single credentials.yml.enc and master.key shared across all environments. For many applications, especially smaller ones, this is perfectly reasonable, since it keeps things simple.

As an application grows, you may want separate credentials per environment so that development and production secrets never mix. Rails supports this with environment-scoped credentials files:

config/credentials/development.yml.enc
config/credentials/development.key
config/credentials/production.yml.enc
config/credentials/production.key

Each environment gets its own encrypted file and its own key. This means a leaked development master key cannot be used to decrypt production secrets, which is a meaningful security boundary if your development environment is less tightly controlled than production.

To create or edit environment-specific credentials:

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

Rails automatically loads the correct environment-specific file when your application boots in that environment, falling back to the default credentials file if no environment-specific file exists.


Using Rails Credentials in Development, Staging, and Production

Development

In development, the master key typically lives in config/master.key on each developer's machine. Since this file is gitignored, every developer needs their own copy. The standard approach is to share the master key through a secure channel, such as a password manager, and have each developer place it in config/master.key locally after cloning the repository.

Never send the master key over Slack, email, or any unencrypted channel. Treat it with the same care as a production database password.

Staging

Staging environments should be treated as close to production as possible, including credential handling. If you use environment-specific credentials, staging can use its own dedicated file, or share the production file if your staging environment mirrors production closely enough to warrant the same secrets. The key principle is that staging should never use looser security practices than production simply because it feels like a lower-stakes environment.

Production

In production, the master key should never be committed to your repository or baked into a public Docker image. Instead, it should be provided to your running application through a secure mechanism appropriate to your hosting platform, which is covered in detail in the next section.


Deploying the Master Key Securely

Your production servers need the master key to decrypt credentials at boot time, but that key must never touch your codebase. There are a few common, secure ways to provide it:

Environment variable. Rails automatically checks for a RAILS_MASTER_KEY environment variable and uses it if config/master.key is not present on disk. Most hosting platforms, including Heroku, Render, and Fly.io, let you set this as a secret environment variable through their dashboard or CLI, which keeps it out of your deployed files entirely.

heroku config:set RAILS_MASTER_KEY=your_actual_master_key_here

Secrets manager. For larger infrastructure, a dedicated secrets manager such as AWS Secrets Manager, HashiCorp Vault, or Doppler can inject the master key into your application's environment at deploy time or boot time. This keeps the key out of your CI configuration and your server's persistent filesystem.

Deployment tooling with encrypted secrets. Tools like Capistrano or Kamal support secure secret injection during deployment, copying the master key onto the server through an encrypted channel rather than including it in your application bundle.

Whichever method you choose, the goal is the same: the master key should exist only in memory or in a tightly access-controlled secrets store on your production infrastructure, never in your Git history, your Docker image layers, or your CI logs.


Common Security Mistakes

Even with Rails Credentials in place, a few mistakes come up repeatedly and undo the protection they provide.

  • Committing config/master.key to Git. This is the most damaging mistake, since it hands over the ability to decrypt every secret in your credentials file to anyone with repository access.
  • Pasting decrypted credentials into chat, tickets, or documentation. Once a secret leaves the encrypted file, it is exposed regardless of how it got there.
  • Logging credential values. Printing a secret to your application logs, even temporarily for debugging, can leave it sitting in log storage or a log aggregation service indefinitely.
  • Reusing the same secrets across environments. Using the same API keys in development and production means a compromised development environment can affect production.
  • Assuming credentials are safe just because they are encrypted. Encryption protects the file at rest, but anyone with the master key and code execution on your server can still read decrypted values in memory. Access control to your servers still matters.
  • Sharing the master key too broadly. Not every contributor needs production credentials. Limit access to the people who actually need it.
  • Skipping credentials in code review. Changes to credentials.yml.enc show up as unreadable ciphertext diffs in pull requests, which makes it easy to approve them without a second thought. Confirm with the author what actually changed rather than approving blindly, especially for production adjustments.

Most of these mistakes come from treating credentials as a one-time setup step rather than an ongoing part of your security practice. Revisit who has access to your master keys periodically, the same way you would review server access or database permissions.


What to Do If Your Master Key Is Exposed

If config/master.key or a RAILS_MASTER_KEY value is ever exposed, whether through an accidental commit, a leaked log, or a compromised machine, treat every secret in that credentials file as compromised immediately.

  1. Rotate the master key and re-encrypt credentials. Do not simply generate a new key in isolation, since the old key will still work if the exposed one leaked separately. Follow the rotation steps in the next section to regenerate both the key and the credentials file.
  2. Rotate every individual secret stored in credentials. Generate new API keys, database passwords, and service tokens with each provider. Assume the exposed values have already been seen by someone who should not have them.
  3. Remove the exposed key from Git history if it was committed. Use a tool like git filter-repo or the BFG Repo-Cleaner to strip the file from your repository's history, then force push and have collaborators re-clone. Removing it from the latest commit alone is not enough, since it remains recoverable in history.
  4. Audit access logs where possible. Check provider dashboards for API keys to see if there was any unexpected usage during the window the key was exposed.
  5. Communicate internally. Make sure your team knows a rotation happened and why, so no one is caught off guard by suddenly invalid credentials.

Speed matters here. The longer a compromised key stays active, the more opportunity there is for misuse.


Rotating Rails Credentials Safely

Rotating credentials means generating a new master key and re-encrypting your secrets, ideally with updated values for anything that may have been exposed.

To rotate safely:

  1. Generate a new master key. Delete the existing config/master.key and config/credentials.yml.enc, then run bin/rails credentials:edit to generate a fresh pair. Note that this means you will need to manually re-enter all of your existing secret values, since the old encrypted file cannot be decrypted without the old key.
  2. Update every individual secret you are rotating. While you have the file open, replace any values tied to the exposure, such as API keys you have regenerated with the relevant provider.
  3. Distribute the new master key securely. Share it with the team members and systems that need it, using a password manager or secrets vault, then update the RAILS_MASTER_KEY environment variable on every server and CI system that references the old key.
  4. Remove the old master key everywhere. Check environment variables, CI secrets, deployment scripts, and any documentation that may reference the previous key.
  5. Deploy and verify. Confirm your application boots correctly in every environment with the new key before considering the rotation complete.

It is worth doing this periodically even without a known exposure, as a routine security practice, particularly for applications handling sensitive user data or payments.


Why You Should Never Hardcode Secrets

It can be tempting, especially early in a project, to drop an API key directly into a controller or initializer just to get something working. This habit causes real problems as a project matures.

Hardcoded secrets end up committed to Git, often permanently, since removing them from the latest commit does not remove them from history. Anyone who forks, clones, or gains access to the repository at any point in its history can find them. They also make it harder to use different values across environments, since a hardcoded value is the same everywhere unless you manually change the code.

Secrets that end up in application logs create a similar problem. A debugging puts statement or an unhandled exception that includes a credential in its message can leave that value sitting in log storage, often accessible to more people than the codebase itself.

Rails Credentials exist specifically to remove the temptation to hardcode secrets. By making it just as easy to reference Rails.application.credentials.dig(:service, :key) as it would be to paste a literal string, there is no convenience trade-off for doing it the secure way.

Treat every secret, from a test API key to a production database password, as something that should never appear in your source code, your commit history, or your logs. Rails gives you the tools to make that easy. Using them consistently is what actually keeps your application secure.

💌 Don’t miss out! Join my newsletter for web development tips, tutorials, and insights delivered straight to your inbox.

Thanks for reading & Happy coding! 🚀

Follow me on:

Code. Learn. Grow.

A friendly newsletter sharing dev tips, lessons, and wins from my journey.