Rails Credentials and Secrets in 2026: Secure Environment Variables Management
Master Rails 8 credentials system for secure secret management. Learn encrypted credentials, environment-specific keys, deployment strategies, and best practices for API keys and database passwords.

Rails 8 credentials provide a secure, encrypted storage system for sensitive configuration data like API keys, database passwords, and third-party service tokens. Unlike environment variables scattered across deployment configurations, credentials live in version control as encrypted files, ensuring consistency across environments while maintaining security.
Rails credentials store secrets in config/credentials.yml.enc, encrypted with a master key in config/master.key. The master key never enters version control—only the encrypted file does. This approach eliminates environment variable sprawl and prevents accidental secret exposure in logs or error messages.
Understanding the Rails Credentials Architecture
The credentials system introduced in Rails 5.2 and refined through Rails 8 consists of three components: the encrypted credentials file, the master key, and the Rails credentials API for accessing values at runtime.
The encrypted file (config/credentials.yml.enc) contains YAML-formatted secrets encrypted using AES-256-GCM. The master key (config/master.key) decrypts this file. Rails automatically loads credentials on boot, making them available throughout the application via Rails.application.credentials.
# config/credentials.yml.enc (decrypted view)
# Access via: Rails.application.credentials
aws:
access_key_id: AKIAIOSFODNN7EXAMPLE
secret_access_key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
region: us-east-1
stripe:
publishable_key: pk_live_51ABC...
secret_key: sk_live_51ABC...
webhook_secret: whsec_...
database:
password: production_db_password_hereThis structure groups related secrets logically. Access nested values using method chaining: Rails.application.credentials.aws.access_key_id returns the AWS key directly.
Editing Credentials with the Rails CLI
The rails credentials:edit command decrypts the credentials file, opens it in an editor, and re-encrypts on save. The editor respects the EDITOR environment variable.
# Edit credentials with default editor
EDITOR="code --wait" rails credentials:edit
# Edit environment-specific credentials (Rails 6+)
EDITOR="vim" rails credentials:edit --environment production
# Show current credentials (read-only)
rails credentials:show
# Show environment-specific credentials
rails credentials:show --environment stagingFor teams using VS Code, the --wait flag ensures Rails waits for the editor to close before re-encrypting. Without it, Rails immediately re-encrypts an empty file.
Set EDITOR permanently in shell configuration (.bashrc, .zshrc) to avoid specifying it each time. For GUI editors, always include wait flags: code --wait for VS Code, subl -w for Sublime Text.
Environment-Specific Credentials for Multi-Stage Deployments
Production, staging, and development environments often require different API keys and database configurations. Rails supports environment-specific credentials files, each with its own master key.
# Create production credentials
rails credentials:edit --environment production
# Creates: config/credentials/production.yml.enc
# Creates: config/credentials/production.key
# Create staging credentials
rails credentials:edit --environment staging
# Creates: config/credentials/staging.yml.enc
# Creates: config/credentials/staging.keyRails loads credentials based on RAILS_ENV. In production, it reads config/credentials/production.yml.enc using config/credentials/production.key. This separation ensures developers cannot accidentally access production secrets.
# config/environments/production.rb
# Rails automatically loads production credentials when RAILS_ENV=production
# Fallback chain: environment-specific -> default credentials
config.require_master_key = trueThe require_master_key setting raises an error on boot if the master key is missing, preventing silent failures in production.
Accessing Credentials in Application Code
Rails provides multiple patterns for accessing credentials depending on the use case. Direct access works for simple lookups, while the dig method handles nested structures safely.
# app/services/payment_service.rb
class PaymentService
def initialize
# Direct access - raises if key missing
@api_key = Rails.application.credentials.stripe.secret_key
# Safe access with dig - returns nil if path missing
@webhook_secret = Rails.application.credentials.dig(:stripe, :webhook_secret)
# With default fallback
@timeout = Rails.application.credentials.dig(:stripe, :timeout) || 30
end
def process_payment(amount:, customer_id:)
Stripe::PaymentIntent.create(
amount: amount,
customer: customer_id,
api_key: @api_key
)
end
endFor credentials used in initializers, access them during configuration:
# config/initializers/stripe.rb
Stripe.api_key = Rails.application.credentials.dig(:stripe, :secret_key)
Stripe.webhook_secret = Rails.application.credentials.dig(:stripe, :webhook_secret)
# Fail fast if critical credentials missing
unless Stripe.api_key
raise "Stripe API key not configured in credentials"
endThis pattern surfaces configuration errors at boot time rather than during runtime requests.
Ready to ace your Ruby on Rails interviews?
Practice with our interactive simulators, flashcards, and technical tests.
Integrating Credentials with Third-Party Services
Most Rails applications integrate with external services requiring authentication. Structure credentials to mirror service organization and validate presence at initialization.
# config/credentials.yml.enc
sendgrid:
api_key: SG.xxxxxxxx
twilio:
account_sid: ACxxxxxxxx
auth_token: xxxxxxxx
phone_number: "+15551234567"
redis:
url: redis://:password@redis.example.com:6379/0
sentry:
dsn: https://key@sentry.io/projectConfigure services in initializers using credentials:
# config/initializers/sentry.rb
Sentry.init do |config|
config.dsn = Rails.application.credentials.dig(:sentry, :dsn)
config.environment = Rails.env
config.traces_sample_rate = Rails.env.production? ? 0.1 : 1.0
end
# config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
config.redis = { url: Rails.application.credentials.dig(:redis, :url) }
end
Sidekiq.configure_client do |config|
config.redis = { url: Rails.application.credentials.dig(:redis, :url) }
endThis approach centralizes secret management while maintaining clear service boundaries.
Deploying with Encrypted Credentials
Deployment platforms need access to the master key to decrypt credentials at runtime. The key can be provided via environment variable or file, depending on the platform.
# Set master key via environment variable
# Rails checks RAILS_MASTER_KEY before looking for master.key file
export RAILS_MASTER_KEY="abc123def456..."
# For environment-specific credentials
export RAILS_MASTER_KEY_PRODUCTION="xyz789..."For containerized deployments, inject the master key at runtime:
# Dockerfile
FROM ruby:3.3-slim
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .
# Do NOT copy master.key into image
# Master key provided at runtime via RAILS_MASTER_KEY
CMD ["rails", "server", "-b", "0.0.0.0"]# docker-compose.yml
services:
web:
build: .
environment:
- RAILS_ENV=production
- RAILS_MASTER_KEY=${RAILS_MASTER_KEY}
ports:
- "3000:3000"Major platforms have specific patterns for secret injection. Heroku uses config vars, AWS uses Secrets Manager or Parameter Store for the master key itself.
Store the master key in CI/CD secret storage (GitHub Secrets, GitLab CI Variables). The credentials file commits to the repository normally—only the key needs secure handling.
Rotating Credentials and Key Management
Regular rotation of secrets reduces exposure from potential leaks. Rails credentials support rotation by editing the file and redeploying.
# Rotate a specific secret
EDITOR="vim" rails credentials:edit
# Update the secret value, save, and close
# Verify the change
rails credentials:show | grep stripeFor master key rotation (rarely needed), create new credentials:
# Backup current credentials
rails credentials:show > /tmp/credentials_backup.yml
# Remove old encrypted file and key
rm config/credentials.yml.enc config/master.key
# Create new credentials with new key
rails credentials:edit
# Paste contents from backup, modify as needed
# Update RAILS_MASTER_KEY in all environmentsAutomate rotation reminders using credential metadata:
# config/credentials.yml.enc
_metadata:
rotated_at: "2026-07-01"
aws:
access_key_id: AKIAIOSFODNN7EXAMPLE
# ... rest of credentialsA scheduled job can check rotation dates and alert when secrets approach expiration.
Testing with Credentials
Test environments need credentials access without exposing production secrets. Rails loads config/credentials/test.yml.enc when RAILS_ENV=test, allowing isolated test credentials.
# Create test credentials
rails credentials:edit --environment test# config/credentials/test.yml.enc
stripe:
secret_key: sk_test_xxx
publishable_key: pk_test_xxx
aws:
access_key_id: test_key
secret_access_key: test_secret
region: us-east-1For unit tests mocking external services, stub credentials directly:
# spec/services/payment_service_spec.rb
require "rails_helper"
RSpec.describe PaymentService do
before do
# Stub credentials for isolated testing
allow(Rails.application.credentials).to receive(:dig)
.with(:stripe, :secret_key)
.and_return("sk_test_mock")
end
describe "#process_payment" do
it "creates a payment intent" do
service = described_class.new
# Test implementation
end
end
endThis approach isolates tests from actual credential values while verifying credential access patterns. For more on testing strategies, see the guide on Rails testing with RSpec.
Credentials vs Environment Variables: When to Use Each
Rails credentials excel for secrets that rarely change and benefit from version control tracking. Environment variables suit values that change per deployment or require dynamic updates without redeploy.
| Aspect | Credentials | Environment Variables | |--------|-------------|----------------------| | Storage | Encrypted in repo | External config | | Version Control | Yes (encrypted) | No | | Rotation | Requires redeploy | Runtime update possible | | Audit Trail | Git history | Platform-dependent | | Team Access | Anyone with master key | Platform RBAC | | Best For | API keys, DB passwords | Feature flags, URLs |
Hybrid approaches work well. Store sensitive secrets in credentials, use environment variables for non-sensitive configuration:
# config/application.rb
config.app_domain = ENV.fetch("APP_DOMAIN", "localhost:3000")
config.redis_url = Rails.application.credentials.dig(:redis, :url) || ENV["REDIS_URL"]This pattern allows flexible deployment while maintaining security for sensitive values. Understanding authentication and authorization patterns helps determine which secrets need the strongest protection.
Conclusion
- Store all sensitive secrets in
config/credentials.yml.enc, never in environment variables or plain text files - Use environment-specific credentials (
--environment production) for multi-stage deployments with separate master keys - Access credentials via
Rails.application.credentials.digfor safe nested lookups with nil fallback - Inject
RAILS_MASTER_KEYat runtime in containerized deployments—never bake the key into images - Create test-specific credentials to isolate test suites from production secrets
- Rotate secrets by editing credentials and redeploying; track rotation dates in credential metadata
- Combine credentials for secrets with environment variables for non-sensitive, frequently-changing configuration
Start practicing!
Test your knowledge with our interview simulators and technical tests.
Tags
Share
Related articles

Rails API Mode in 2026: RESTful APIs, Serialization and Best Practices
Master Rails API mode with best practices for RESTful design, JSON serialization with Alba and jsonapi-serializer, authentication strategies, and error handling in Rails 8.

Solid Queue and Solid Cache in Rails 8: Complete Guide for Technical Interviews 2026
Deep dive into Solid Queue and Solid Cache, the database-backed defaults in Rails 8. Architecture, configuration, concurrency controls, and interview-ready knowledge for 2026.

Ruby on Rails 8: New Features and Migration Guide 2026
Ruby on Rails 8 ships with the Solid Trifecta, a built-in authentication generator, Kamal 2 deployment, and Propshaft. This tutorial covers every major feature and walks through upgrading from Rails 7 step by step.