Docs · Bring Your Own Keys

Optional Integrations

Turnstile bot check and the general shape of everything else that's optional.

Past the secret key base, email, and billing, everything else the kit talks to is genuinely optional, and every one of them follows the same adapter+fake shape: absent credentials mean a deterministic fake stands in, and the feature it's part of still works end to end. See The Adapter+Fake Pattern for the mechanism behind this.

Bot check: Cloudflare Turnstile

TURNSTILE_SITE_KEY and TURNSTILE_SECRET_KEY. Off by default, meaning a no-op that always passes; once both are set, the Turnstile widget renders on the sign-in form and every submission is verified against Cloudflare before a code is sent.

S3-compatible object storage

AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, S3_BUCKET, S3_REGION, and S3_ENDPOINT for a non-AWS provider like Cloudflare R2. Without these, Active Storage falls back to local disk. See Production Database and Storage.

APP_HOST

Your production hostname. This one isn't a third-party credential, but it belongs in the same "set it before you rely on production behaving correctly" category: it's what canonical URLs, the sitemap, and the feeds use to build absolute links, and mailer links read it too.

Mobile: App Store and Play Store

Shipping the native apps needs an Apple Developer Program membership ($99/year), a Google Play Console account ($25 one time), signing certificates or a keystore, and, if you're offering in-app purchases, StoreKit and Play Billing product setup in each store's console. None of this is needed to develop or even deploy the web app; it's specific to the mobile shells. See Mobile Overview.

The pattern, if you're adding your own key

Every credential in the app resolves from ENV first, then Rails encrypted credentials as a fallback, and every integration built around a credential has a fake that runs without it. If you're wiring up a new third-party service yourself, follow the same shape; see The add-integration Skill.

Next

You've now covered the full credential reference. See how to pull kit updates into your product without losing your own work: Pulling Kit Updates.

Common 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.

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.

What is the minimum set of keys needed to launch an app?

RAILS_MASTER_KEY is the only one production will not boot without. APP_HOST is not a secret but belongs in the same pass, because without it every emailed link points at localhost. Add a Stripe key when you want to charge and a Resend key when you want mail to leave the building; both run on fakes until then.

Why do my app's emails link to localhost after deploying?

A mailer runs in a background job with no incoming request, so it cannot infer your domain. It reads APP_HOST instead, and without that set it falls back to the development default. Set APP_HOST to your domain, redeploy, and every mailer link, canonical tag and sitemap URL becomes absolute and correct.