---
title: "Swap a driver"
description: "Change the provider behind an interface by editing main.yaml, prove it with tests and mainsdk check, and fail over or route by market."
section: "guides"
canonical: "https://mainsdk.dev/docs/guides/swap-a-driver"
updated: "2026-10-28"
---

# Swap a driver

> Change the provider behind an interface by editing main.yaml, prove it with tests and mainsdk check, and fail over or route by market.

Canonical: https://mainsdk.dev/docs/guides/swap-a-driver · Updated: 2026-10-28

Move Pinecart's email from Amazon SES to Resend without changing any code. Your code calls an interface, such as `email.send()`; the driver named in `main.yaml` talks to the provider. Changing provider is a config change. See [Interfaces and drivers](https://mainsdk.dev/docs/concepts/interfaces-and-drivers).

**Before you start:** an account and an API key with the new provider, and tests for the code that sends email (see [Test your app](https://mainsdk.dev/docs/guides/testing)).

How seamless a swap is depends on whether the provider holds state:

- **Stateless** (email, SMS, push, webhooks out, realtime, AI): change the driver and you are done. This guide covers that case.
- **Stateful** (auth, payments, data): users, customers and rows have to move; see the section on stateful swaps below.

## 1. Store the new key

Add `RESEND_API_KEY` to your secrets driver (for example `.mainsdk/secrets.json` locally, or your host's environment variables in production). See [Secrets](https://mainsdk.dev/docs/interfaces/secrets).

## 2. Change the driver

```yaml title="main.yaml"
email:
  driver: resend          # was ses: this is the only change
  key: secret:RESEND_API_KEY
```

The Resend driver declares its own host (`api.resend.com`), so your `network.allow` list doesn't change.

## 3. Verify it worked

Run your tests, then the check:

```bash
node --test
npx mainsdk check
```

```text
$ npx mainsdk check
mainsdk check · pinecart · env dev · Main 27
✓ config
✓ secrets
✓ policy
✓ network
✓ data
all gates passed · exit 0
```

Every listed driver passes the same conformance suite for its interface version, so a swap between listed drivers keeps the same guarantees. If the new driver lacks a capability your app uses (for example attachments), `mainsdk check` names the gap before production instead of failing silently.

The product requirements also describe a `mainsdk swap` command that runs the contract tests against the new driver and sends in shadow mode before switching. It has no spec yet, so its phase, flags and output are not decided.

## Fail over instead of swapping

List more than one driver to fail over when the first is down:

```yaml title="main.yaml"
fallback:
  email: [resend, ses]
```

Prove the failover in CI with a chaos drill; see [Test your app](https://mainsdk.dev/docs/guides/testing).

## Route by market

One deployment can use a different driver per market. Market resolves per request.

```yaml title="main.yaml"
payments: { in: razorpay, default: stripe }
```

## Stateful swaps: auth, payments, data

Users in an auth provider, customers in a payment provider and rows in a database need a migration. MainSDK runs it as a guided job with a rollback, never a silent switch. Moving a user between data regions is likewise an audited job.

> **Warning:** Plan a stateful move like any migration: lock your key flows first, run it on a branch, and keep the old provider until the job reports done. How the guided job is started, and its rollback steps, are not specified yet.

## Run two major versions side by side

When a driver needs a new major version of an interface, run both during the move and upgrade one call site at a time:

```ts
import { email } from "mainsdk/email";              // email@1
import { email as emailV2 } from "mainsdk/email/v2";
```

A deprecated field keeps working for at least 12 months after it is deprecated, and every breaking change names its codemod.

## Next

- [Interfaces and drivers](https://mainsdk.dev/docs/concepts/interfaces-and-drivers)
- [Test your app](https://mainsdk.dev/docs/guides/testing)
- [Eject](https://mainsdk.dev/docs/guides/eject)
