Optional services
Learn which external services Saavo needs for local development and initial deployment, then add payments, sign-in, analytics, and notifications as your product needs them.
The Saavo template includes integration points for many third-party services, but you do not need to register for all of them before creating a project. This chapter collects their registration and integration guides. For now, it explains when configuration is needed and where it belongs.
Requirements by stage
| Stage | External services to configure |
|---|---|
| Project creation | No additional third-party accounts are needed. Use the Turnstile test keys included with the template. |
| Local development | Connect only the feature you are currently developing. Stripe, OAuth, analytics, and notification settings can remain empty. |
| Initial deployment | Follow the deploy:init prompts to prepare Turnstile and the settings required by your current email service. You can use Turnstile test keys if you do not have a production domain yet, and you can skip Stripe. |
| Before launch | Replace the Turnstile test keys with real keys for your production domain. Check OAuth callbacks, payment webhooks, and production settings for other enabled services. |
Production settings are not needed to create a project
Create a project with Saavo CLI:
npx saavo-cli@latest create my-projectIf you accept local environment initialization, the CLI installs dependencies and calls the template's own saavo:init. This creates .env, generates a local SAAS_SECRET, retains the Turnstile test keys, and initializes the local database.
If you skipped local initialization during project creation, enter the project directory and run:
npm install
npm run saavo:initYou do not need production keys for Resend, Stripe, GitHub, Google, or similar services at this stage. Run npm run dev first to confirm that the project starts correctly, then decide which services to connect.
Add services as you develop each feature
The local .env file is only for development. Leave unused variables as empty strings. Do not enter arbitrary placeholders just to fill the file.
| Feature you are developing | What to prepare | Effect if not configured |
|---|---|---|
| Sending email in production | A Resend API key, or a switch to Cloudflare Email | Registration emails, verification codes, and password recovery emails cannot be delivered |
| Stripe purchase flow | Stripe test keys, a connection ID, a webhook secret, and real test Price IDs | Pricing can be displayed, but Checkout cannot complete |
| GitHub sign-in | Client ID and Client Secret for a GitHub OAuth App | The GitHub sign-in option is not enabled |
| Google sign-in | Client ID and Client Secret for a Google OAuth client | Google sign-in and One Tap are not enabled |
| Third-party analytics or advertising | Site IDs, tokens, or other settings from the chosen platform | The corresponding scripts do not load |
| External notifications | A webhook, bot token, or signing key | Events are not sent to external channels |
Regular file uploads do not require R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, or R2_SECRET_ACCESS_KEY. The template accesses buckets through the Worker's MAIN_R2 binding. These three variables are mainly for direct R2 API access, such as signed downloads of release archives.
Collect settings during the initial deployment
When you are ready to deploy to Cloudflare for the first time, run:
npx wrangler login
npm run deploy:initdeploy:init selects the Cloudflare account, confirms the Worker and resource names, collects production settings, and creates .env.production. With the template's current defaults, focus on these settings:
- Turnstile: Enabled by default. Neither the Site Key nor the Secret Key can be empty. You can enter Cloudflare's official test keys for an initial deployment to
workers.dev. - Email: Resend is the default, so
RESEND_API_KEYis required. If you have switched to Cloudflare Email, the deployment script configures theEMAILbinding instead. - Stripe: The deployment process asks whether to configure it now. You can skip it for the time being.
- OAuth, analytics, and notifications: Leave disabled services empty. Later, add their settings to
.env.productionand runnpm run deploy:update.
Local .env and production .env.production each serve a separate environment. Do not overwrite one with the other:
| File | Purpose | Turnstile |
|---|---|---|
.env | Local development | Keep the Cloudflare test keys |
.env.production | Remote deployment | Test keys can be used temporarily for initial verification. Replace them with keys from a real widget before opening the site to users. |
.env.production is already ignored by Git. Saavo's deployment script synchronizes its public values as Worker variables and its sensitive values as secrets. Do not bypass it to maintain a separate set of remote settings.
Common configuration locations
Third-party services usually need both feature configuration and environment variables. Adding keys alone does not necessarily switch providers, and changing configuration alone cannot grant access.
| Service | Feature configuration | Local and production settings |
|---|---|---|
| Turnstile | config/deploy.ts → auth.useTurnstile | CLOUDFLARE_TURNSTILE_* |
config/deploy.ts → emailProvider | RESEND_API_KEY or the EMAIL binding | |
| Payments | config/payment.ts, config/products.ts | STRIPE_* |
| OAuth sign-in | config/deploy.ts → auth / ui | GITHUB_*, GOOGLE_* |
| Third-party analytics | config/analytics.ts | Platform-provided IDs, tokens, or site identifiers |
| Advertising | config/ads.ts | A site ID from the advertising platform |
| Notifications | config/notifications.ts | A webhook, bot token, or signing key |
Restart npm run dev after changing .env. After changing .env.production, projects that have completed their initial deployment use:
npm run deploy:updateAvailable tutorials
- Configure Turnstile: Complete the initial deployment, then create a widget for your production domain, replace the keys, and verify the client and server flows.
- Configure domains: Register a domain directly with Cloudflare or connect one purchased from another registrar, then configure your website, email, and an R2 custom domain.
- Configure Resend: Verify a domain, create an API key with restricted permissions, and connect Saavo's registration, password recovery, and security notification emails.
- Configure GitHub OAuth: Create an OAuth App, register local and production callback URLs, and configure the Client ID and Client Secret.
- Configure Google OAuth: Configure Google Auth Platform and a Web application client to enable regular Google sign-in and optional One Tap.
Planned tutorials
More pages will be added in the categories below. An entry without a link means its tutorial has not been written yet, not that the template lacks support.
- Email: Cloudflare Email
- Payments: Stripe
- Cloudflare features: R2 API tokens and signed downloads
- Analytics and advertising: Google Analytics, Microsoft Clarity, Cloudflare Web Analytics, Umami, Plausible, PostHog, Google AdSense, and others
- Notification channels: Slack, Discord, Telegram, Microsoft Teams, Feishu, DingTalk, WeCom, and generic webhooks
example.vars still contains PADDLE_* variables, but config/payment.ts currently allows only Stripe. Do not register for Paddle just because these variables are present. A corresponding tutorial will be added once the template officially supports Paddle.
If you are only preparing your development environment, continue to Create a project. Return to this chapter to configure production services when you need to deploy.