Every capability in a molecule app sits behind an interface with swappable providers — change vendors by changing one line, not rewriting the app.
A core package is an interface plus an accessor — never a concrete implementation. A bond package is a swappable provider that implements it. Your app’s bonds.ts wires which provider is live — that is configuration, not coupling:
// interface — what the app codes against
import { bond } from '@molecule/api-bond'
// provider — one swappable implementation
import { mailgun } from '@molecule/api-emails-mailgun'
bond('emails', mailgun)Application code asks the category for the interface and never learns which vendor is behind it. Categories with several live providers (like ai) use named bonds — bond('ai', 'anthropic', ai) — so they coexist.
Because every provider implements the same interface, swapping is mechanical — one command rewrites the wiring, migrations included where needed:
npx mlcl swap @molecule/api-database-mysql # Postgres → MySQL
npx mlcl swap @molecule/api-emails-smtp # Mailgun → plain SMTPNothing else in the app changes: same handlers, same calls, different vendor. This is the property the whole ecosystem is built on — decoupling first. Stripe → another processor, one OAuth provider for another, one AI host for another: all one-line moves.
| Category | Providers include |
|---|---|
database | PostgreSQL, MySQL, SQLite, D1/Cloudflare |
ai | Anthropic, OpenAI, DeepSeek, Moonshot, Z.ai — named bonds per provider |
emails | Mailgun, SMTP |
payments | Stripe and other processors |
auth | OAuth providers, password auth |
files / storage | local, S3-compatible |
code-sandbox | Docker, E2B, remote microVM hosts |
The authoritative list for any category is the catalog: npx mlcl search <category> or the packages pages.