Answers · Keys & Services

How do I tell which integrations are live in production?

Ask the adapters at runtime rather than reading environment variables. Each one chooses a real client or a local fake based on whether its credential is present, so querying the adapter tells you what the app is actually doing. A variable that is set but misspelled looks configured and behaves like a fake.

Ask the app, not the config

bin/kamal app exec --interactive --reuse 'bin/rails console'
Billing.for(Account.first).class
ActiveStorage::Blob.service.name
ActionMailer::Base.delivery_method
Rails.application.config.x.app_host

Four lines, four of the things most likely to be silently wrong. Each returns what is live rather than what you believe you configured.

Why reading the variables is not enough

Three failure modes all look identical from the outside:

  • The variable is misspelled, so it is unset as far as the app is concerned.
  • It is set on your laptop and not on the server.
  • It is set in .kamal/secrets but that file did not export it, so the value is empty.

In every case the adapter falls back to its fake, the app works, and nothing reports a problem. That graceful degradation is exactly what makes a fresh clone usable and exactly what hides a misconfiguration in production.

The two that fail loudest

RAILS_MASTER_KEY is missing: the app does not boot, so you find out on the first deploy.

MAIL_FROM names an unverified domain: the provider rejects the send, which raises in the job and lands in the log rather than passing silently.

Everything else degrades quietly.

Make it a habit after each deploy

bin/kamal secrets print
curl -sI https://yourdomain.com/up | head -1
curl -s https://yourdomain.com/sitemap.xml | head -3

The third one is the cheap check for APP_HOST: if the first URL in the sitemap is localhost, several other things are wrong in the same way, including every link in every email.

Check the list itself

docs/BRING_YOUR_OWN_KEYS.md lists every variable the app reads. Going down it once after the first deploy, deciding which you want live and confirming each, takes about ten minutes and is the only time you will have the whole picture in your head.

Related questions

Do I need API keys to run a Rails starter kit locally?

No. Billing, email, bot checking and error reporting each sit behind an adapter that returns a real client when its credential is present and a deterministic local fake when it is not. A fresh clone runs bin/setup and bin/dev with no keys, and checkout, sign-in and gated features all work end to end.

How do I stop bot signups on a Rails sign-up form?

Set TURNSTILE_SITE_KEY and TURNSTILE_SECRET_KEY. app/adapters/bot_check.rb returns a real Cloudflare Turnstile verifier when both are present and a pass-everything fake when they are not, so the form works in development with no account and starts blocking bots in production without a code change.

How do I store uploaded files on S3 instead of local disk?

Set S3_BUCKET, S3_REGION, AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, plus S3_ENDPOINT for a non-AWS provider. config/storage.yml already defines the service, so production uses object storage instead of the container's disk. Existing files on local disk do not move by themselves.