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.
• 15 min read
• 15 min read
Learn how Rails Credentials work: encrypt secrets, secure your master key, and manage config safely in development and production.
• 15 min read
• 15 min read
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.
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:
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.
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 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 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.
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:
credentials.yml.enc using config/master.keycredentials.yml.encIf 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.
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.
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.
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.
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 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.
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.
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 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.
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.
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.
Even with Rails Credentials in place, a few mistakes come up repeatedly and undo the protection they provide.
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.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.
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.
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.Speed matters here. The longer a compromised key stays active, the more opportunity there is for misuse.
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:
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.RAILS_MASTER_KEY environment variable on every server and CI system that references the old key.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.
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.