Swap a provider
Change the company that handles your payments, your email or your file storage, without rewriting your app.
zap.ts keeps outside companies behind its own packages. Your app calls
@zap-ts/mail, not Resend. It calls @zap-ts/billing, not Stripe.
So changing company is a settings change or a two-line change, not a rewrite.
This page covers the four you are most likely to change.
Email is the easiest. You change one setting.
Open the root .env.schema and find:
MAIL_PROVIDER=smtp
MAIL_PROVIDER accepts one of six values:
| Value | What it does |
|---|---|
smtp |
Sends to Mailpit on your computer. The default |
console |
Prints the email to your terminal instead of sending it |
resend |
Sends with Resend |
postmark |
Sends with Postmark |
sendgrid |
Sends with SendGrid |
brevo |
Sends with Brevo |
Pick one, then add its key. For Resend:
MAIL_PROVIDER=resend
RESEND_API_KEY=re_your_real_key
Put the real key in your .env.local, not in the schema.
If you name a provider and forget its key, the app stops and says so:
RESEND_API_KEY is required when MAIL_PROVIDER is "resend"
No code changes. Your emails are unchanged. See Mail.
File storage
Storage speaks one shared protocol that most storage services support, including Cloudflare R2 and MinIO.
Because they all speak the same protocol, you only change where you point.
On your computer, the settings point at MinIO:
R2_ACCOUNT_ID=zap_dev_r2_account
R2_ACCESS_KEY_ID=minioadmin
R2_SECRET_ACCESS_KEY=minioadmin
R2_BUCKET=zap
R2_ENDPOINT=http://127.0.0.1:9000
For a real service, put in your own account details and bucket name.
R2_ENDPOINT is the address of the storage service. Leave it empty when you
use Cloudflare R2 — R2 is worked out from the account ID. Set it when you use
anything else.
No code changes. See Storage.
Payments
Payments need a code change, because each company stores subscriptions slightly differently. It is still small: two import paths.
Seven companies are supported: Stripe, Polar, Chargebee, Dodo Payments, Creem, Autumn and Commet.
Step 1. Open packages/billing/src/server.ts. Change the import path:
export { ... } from "./polar/server";
Step 2. Open packages/billing/src/client.ts. Change it to match:
export { ... } from "./polar/client";
Step 3. Add that company’s keys to your .env.schema and .env.local.
Step 4. Open packages/billing/src/plans.ts. Each plan already has a line
for every company. Fill in the one for your new company with the real IDs from
its dashboard.
Step 5. Update the database:
pnpm run auth:generate
pnpm run db:migrate
You need this because the new company saves different fields. The first command rewrites the table definition. The second applies it.
Nothing else in your app changes. Every company exports the same function names, so your pages keep working. See Billing.
AI models
AI is the one swap that lives in code, because each company ships its own
adapter package. packages/ai/src/index.ts names the createOpenai*
functions in three places: the imports, the AIAdapters type and the AILive
layer. Change those three, change DEFAULT_MODELS to the names the new
company uses, and declare its API key in the root .env.schema.
The seven adapters are independent, so you can keep text on one company and speech on another. AI has the steps, the list of adapter packages, and which capabilities each one covers.
Why this works
Each package exports the same names no matter which company is behind it.
Your app never imports stripe or resend directly. If it did, swapping
would mean finding every one of those imports.
Keep it that way in your own code. Import from @zap-ts/mail, not from the
mail company.
Related
- AI — how models are called
- Billing — how payments are set up
- Mail — how email is sent
- Storage — how files are stored
- Going to production — the full checklist