Built-in and local drivers
The drivers that ship inside MainSDK - local drivers for offline development, built-in production drivers, action surfaces and testing fakes.
Some drivers need no third-party account because they ship inside MainSDK. They fall into two groups. Local drivers let mainsdk dev run your app offline, with no provider keys and no network calls to providers. Built-in drivers are production drivers that run in your app: Cedar for permissions and policy, the network allowlist, rate limits, privacy, webhooks, PDFs and more. This page covers both, plus the action surfaces, MainSDK Cloud as a destination, a few generic slots and the testing fakes. SQLite for local data has its own page: SQLite.
Interfaces it serves
Pick Built-in and local drivers in main.yaml for any of these. Your calls stay the same, and you can swap later.
authBuilding for 0.3Driver local Local (development only)
auth:
driver: localSwap to another provider
connectionsBuilding for 0.3Driver local Local (tests and local mode
connections:
driver: localverifyBuilding for 0.7Driver local Local outbox for development and tests
verify:
driver: localSwap to another provider
tenantBuilding for 0.3Driver builtin Built in (coreDefault
tenant:
driver: builtinapikeysBuilding for 0.3Driver local Local (tests and local mode)
was memory
apikeys:
driver: localSwap to another provider
accessBuilding for 0.3Driver cedar Cedar (built in)Default
access:
driver: cedarSwap to another provider
policyBuilding for 0.2Driver builtin Cedar (built inDefault
policy:
driver: builtinSwap to another provider
contextBuilding for 0.4Driver builtin Built in (the app link)Default
context:
driver: builtincalendarBuilding for 1.2Driver local Local (tests and mainsdk dev)
calendar:
driver: localSwap to another provider
importsBuilding for 0.4Driver builtin Built in parsers for CSV, XLSX, JSON and NDJSONDefault
imports:
driver: builtinSwap to another provider
kvBuilding for 0.3Driver local Local (memory or one file)Default
kv:
driver: localSwap to another provider
cacheBuilding for 0.4Driver local In-process only
cache:
driver: localSwap to another provider
searchBuilding for 0.4Driver local Local (in process
search:
driver: localfeedsBuilding for 0.4Driver local Local (in process
feeds:
driver: localSwap to another provider
syncBuilding for 1.1Driver local Local (in memoryDefault
sync:
driver: localSwap to another provider
aiBuilding for 0.3Driver local Local (no accountDefault
with no ai.driver the app runs the fake driver (driver: fake); local is the same kind, scripted or echoing replies, for dev and tests
ai:
driver: localSwap to another provider
actionPreviewDriver mcp MCP
action:
driver: mcpSwap to another provider
actionPreviewDriver http HTTP API
action:
driver: httpSwap to another provider
actionPreviewDriver server-action Server actions
action:
driver: server-actionSwap to another provider
actionPreviewDriver cli CLI
action:
driver: cliSwap to another provider
agentsBuilding for 0.3Driver builtin Built inDefault
agents:
driver: builtinmemoryBuilding for 0.4Driver local Local (SQLite or JSONL)
memory:
driver: localSwap to another provider
advisorBuilding for 0.6Driver builtin Built in (calls the ai interface)Default
advisor:
driver: builtinpayBuilding for 0.3Driver local Local test cards
payments:
driver: localmeterBuilding for 0.3Driver local Local (tests and mainsdk dev)
meter:
driver: localentitlementsBuilding for 0.3Driver local Local (tests and local mode)
was memory
entitlements:
driver: localSwap to another provider
licenceBuilding for 0.4Driver local Local (a dev licence from the test root)
licence:
driver: localSwap to another provider
licenceBuilding for 0.4Driver http HTTP refresh (MainSDK Cloud or your own issuer)
licence:
driver: httpSwap to another provider
notifyBuilding for 0.3Driver local Local terminal channel
notify:
driver: localengagementBuilding for 0.4Driver builtin Built in on notify and workflowsDefault
engagement:
driver: builtinemailBuilding for 0.3Driver local Local inbox
email:
driver: localSwap to another provider
mailBuilding for 1.2Driver local Local (tests and mainsdk dev)
mail:
driver: localrealtimeBuilding for 0.3Driver local Local (one instance)
realtime:
driver: localSwap to another provider
filesBuilding for 0.3Driver local Local files on disk
files:
driver: localSwap to another provider
shareBuilding for 0.3Driver local Local links on the dev server
share:
driver: localSwap to another provider
linksBuilding for 0.4Driver local Local links on the dev server
links uses the share driver
links:
driver: localSwap to another provider
mediaBuilding for 0.4Driver local Local placeholder driver (right structure
media:
driver: localSwap to another provider
moderateBuilding for 0.4Driver builtin Built in on dbDefault
moderate:
driver: builtinpdfPreviewDriver builtin Built inDefault
pdf:
driver: builtindocumentsPreviewDriver builtin Built inDefault
documents:
driver: builtinSwap to another provider
webhooksPreviewDriver builtin Built inDefault
webhooks:
driver: builtinSwap to another provider
workflowsPreviewDriver local Local (in memory in tests, a journal folder in development)
workflows:
driver: localSwap to another provider
computeBuilding for 0.6Driver local Local program (system.run)Default
compute:
driver: localjobsBuilding for 0.3Driver local In-process local queue
built; memory or files that survive mainsdk dev restarts
jobs:
driver: localSwap to another provider
secretsBuilding for 0.2Driver env Environment variables
secrets:
driver: envSwap to another provider
secretsBuilding for 0.2Driver local Local file
secrets:
driver: localSwap to another provider
keysBuilding for 0.3Driver local Local (development only)
keys:
driver: localSwap to another provider
cryptoBuilding for 0.3Driver cloud-kms Cloud key services
planned; use the keys interface today
crypto:
driver: cloud-kmsSwap to another provider
cryptoBuilding for 0.3Driver builtin WebCryptoDefault
crypto:
driver: builtinSwap to another provider
e2eBuilding for 1.2Driver local Local fake (not for production)
e2e:
driver: localSwap to another provider
networkBuilding for 0.3Driver builtin Built inDefault
network:
driver: builtindiskBuilding for 0.3Driver builtin Built inDefault
disk:
driver: builtinsystemBuilding for 0.3Driver builtin Built inDefault
system:
driver: builtinnetBuilding for 0.4Driver builtin Built inDefault
net:
driver: builtinworkersBuilding for 0.4Driver builtin Built inDefault
workers:
driver: builtinsandboxBuilding for 0.4Driver local Local subprocess (development)
sandbox:
driver: localSwap to another provider
limitsBuilding for 0.3Driver local Local (in process)Default
limits:
driver: localprotectBuilding for 0.4Driver local Local fake TAPS NodeDefault
protect:
driver: localSwap to another provider
privacyBuilding for 0.3Driver builtin Built inDefault
privacy:
driver: builtinbackupBuilding for 1.2Driver object-lock Object storage with object lock
backup:
driver: object-lockSwap to another provider
backupBuilding for 1.2Driver local Local (tests and drills without a provider)
backup:
driver: localSwap to another provider
statusBuilding for 0.4Driver builtin Built inDefault
status:
driver: builtinSwap to another provider
statusBuilding for 0.4Driver provider Your status page provider
status:
driver: providerSwap to another provider
securityBuilding for 0.3Driver builtin Built in (log, OTLP and events sinks)Default
security:
driver: builtinincidentBuilding for 0.4Driver builtin Built in (pushes through the config driver)Default
incident:
driver: builtincanaryBuilding for 0.4Driver builtin Built in (an Aho-Corasick matcher on the standard library)Default
canary:
driver: builtinalertsBuilding for 0.4Driver builtin Built in (sends through notify and email drivers)Default
alerts:
driver: builtinsignalsBuilding for 0.4Driver builtin Built in (diagnostics channels, events.broadcast and the host bus)Default
signals:
driver: builtinplaybooksBuilding for 0.4Driver builtin Built inDefault
playbooks:
driver: builtinlogBuilding for 0.2Driver terminal TerminalDefault
telemetry:
to: terminalSwap to another provider
logBuilding for 0.2Driver mainsdk MainSDK Cloud
telemetry:
to: mainsdkSwap to another provider
observeBuilding for 0.3Driver builtin Built in (coreDefault
observe:
driver: builtinanalyticsBuilding for 0.3Driver builtin Built in (on db)Default
analytics:
driver: builtinSwap to another provider
normsBuilding for 0.4Driver builtin Built inDefault
norms:
driver: builtini18nPreviewDriver files Local YAML filesDefault
i18n:
driver: filesi18nPreviewDriver ai-draft AI draft with human review
i18n:
driver: ai-draftgeoBuilding for 0.7Driver platform-headers Platform headersDefault
a hint from the declared platform; no geocoder
geo:
driver: platform-headersSwap to another provider
geoBuilding for 0.7Driver local Local table in the testing kit
geocodes from a table with no network, for tests
geo:
driver: localSwap to another provider
updatesBuilding for 0.7Driver local Local fake for tests and developmentDefault
answers from a script; records every call
updates:
driver: localSwap to another provider
feedbackBuilding for 0.6Driver builtin Built inDefault
feedback:
driver: builtinneighboursBuilding for 0.4Driver builtin Built in (user-only sockets and the app link)Default
neighbours:
driver: builtinappsBuilding for 0.4Driver builtin Built in (a local folder and a user-only socket)Default
apps:
driver: builtinopsBuilding for 0.4Driver builtin Built in (a user-only socket and a token file)Default
ops:
driver: builtindeviceBuilding for 1.3Driver local Local (did:key, Ed25519 or P-256, no dependency)Default
device:
driver: localSwap to another provider
configBuilding for 0.2Driver files Files
config:
driver: filesSwap to another provider
configBuilding for 0.2Driver local Local (in process)
was memory; for tests and several instances in one test process
config:
driver: localSwap to another provider
schemaBuilding for 0.2Driver builtin Built inDefault
schema:
driver: builtinapiBuilding for 0.3Driver builtin Built in core moduleDefault
api:
driver: builtintestingBuilding for 0.4Driver local The local drivers with recording and chaosDefault
testing:
driver: localadoptBuilding for 0.5Driver builtin Built in (reads files, runs git)Default
adopt:
driver: builtinbotsBuilding for 0.3Driver local In-process counters (the default store; no third party)
bots:
driver: localSwap to another provider
connectorsBuilding for 1.2Driver local Local mock (tests and mainsdk dev)
connectors:
driver: localBefore you start
There is nothing to create: no account, no keys, no dashboard. Two things to know:
- Local drivers are for development and tests.
mainsdk check --env prod, or any run whose resolved environment isprod, fails withMAIN-CHECK-0026if any interface resolves to a local driver. Thekeyslocal driver also fails withMAIN-KEYS-0001in production. - Built-in drivers are production-ready. Cedar,
network,limits,privacy,webhooks,pdf,status,analytics,feedback,i18nfiles,configfiles andgeoplatform headers are the default or only driver for their interface and are meant to run in production.
Keep local drivers in a development overlay (main.env.dev.yaml) and real providers in main.env.prod.yaml, so the check keeps them apart.
Configure
Local development drivers
mainsdk dev runs a local driver for every interface in use, so the app works end to end with no cloud account.
auth: local- sign-in for development only, with no identity provider.ai: local- a local fake model, with redaction, caps and audit enforced as in production.pay: local- local test cards. With no provider key, a checkout completes and firespayment.succeeded.notify: local- the terminal channel. WhatsApp and SMS messages print in the terminal. The key that selects it is not decided yet.email: local- a local inbox. Emails land there so you can see the rendered message and its headers.files: local- files on disk. In production, usegetqr,s3,uploadthingorvercel-blob(ADR-0013);checkrefuses the local driver in production.jobs: local- an in-process queue for events and background jobs.secrets: local- reads.mainsdk/secrets.json, which is git-ignored.secrets: env- reads the process environment. Whetherchecktreats it as a local driver in production is not specified; prefer a secrets manager with workload identity there.keys: local- local envelope encryption, development only.
ai:
driver: local
email:
driver: local
files:
driver: local
jobs:
driver: local # [to be decided] driver id for the in-process local queue
secrets:
driver: local
keys:
driver: localBuilt-in production drivers
access: cedar- permissions decided in process with Cedar, RBAC and ABAC, deny by default.policy: cedar- policies from yourpolicies/folder, decided in process, inobserve,warnorenforcemode.network: builtin- the outbound allowlist; undeclared hosts are blocked and reported.limits: builtin- rate limits, locks and quotas, with sign-in and AI calls limited by default.privacy: builtin- export, erasure and consent across every other driver, with retention per data label.webhooks: builtin- signed outbound delivery with retries, and verified inbound webhooks.pdf: builtin- renders PDFs from templates, localised throughi18n, and signs them.status: builtin- health checks per dependency and a status page.analytics: builtin- the built-in store; active users by country, region and version are queries, and IP addresses are never stored.feedback: builtin- report capture with the trace, version and steps attached.i18n: files- messages in local YAML files;i18n: ai-draftadds an AI draft for new strings, marked as needing review until a person approves it.config: files- typed settings from files; where it reads its values from is not decided yet.geo: platform-headers- a coarse location hint from the headers your hosting platform adds, never used for access.
access:
driver: cedar
models: [rbac, abac]
policy:
engine: cedar
dir: policies/
mode: observe
network:
allow: [api.partner.com]
default: deny
webhooks:
driver: builtin
secret: secret:WEBHOOK_SIGNING_KEY # suggested name
i18n:
driver: files
locales: [en-IN, hi-IN]
config:
driver: files
schema: ./config.schema.jsonlimits, pdf, status, feedback and geo take driver: builtin (or platform-headers) and nothing else so far. network and privacy have one driver, so there is nothing to set.
Action surfaces
mcp, http, server-action and cli are not drivers you choose. One action() definition gives you an HTTP endpoint, a server action, a CLI command (mainsdk run <name>) and an audit event, plus an MCP tool when you opt in with mcp: true or mcp.expose.
mcp:
expose: [orders.refund, orders.list]
confirm: { write: true, destructive: true }MainSDK Cloud as a destination
log: mainsdk and analytics: mainsdk send telemetry and product events to MainSDK Cloud. Nothing leaves your app before mainsdk login, and then only when you opt in. log: terminal is the default and keeps everything local.
telemetry:
to: [terminal, mainsdk] # default [terminal]Generic slots
status: provider- your own status page provider. Which providers are supported is not decided yet.crypto: cloud-kms- cloud key services behindcrypto. Key names and references are not decided yet.backup: object-lock- object storage with object lock, for immutable backups. How you select it is not decided yet.
Testing fakes
testing: fakes is the only driver of the testing kit: an in-memory fake for every interface, generated from its contract. It has no main.yaml block; createTestApp() reads your file and swaps each interface for its fake.
Use it
Your code is the same on a local driver and a real provider. With email: local, this lands in the local inbox:
"use server";
import { email } from "mainsdk";
export async function welcome(address: string) {
await email.send({ to: address, template: "welcome", data: {} });
}A built-in production driver, Cedar, deciding in process:
import { access, auth } from "mainsdk";
export async function PATCH(req: Request, { params }: { params: { id: string } }) {
const session = await auth.require(req);
const order = { type: "order", id: params.id };
const decision = await access.check({ subject: session.user, action: "orders.update", resource: order });
if (!decision.allow) return new Response("Forbidden", { status: 403 });
return Response.json({ ok: true });
}Local development and testing
npx mainsdk devpnpm mainsdk devmainsdk dev uses local drivers with no network calls to providers. In tests, createTestApp() from @mainsdk/testing puts every interface on its fake, clock.advance() controls time, and chaos.on("<interface>", { outage: true }) injects outages.
import { it } from "node:test";
import { createTestApp, expect, mailbox } from "@mainsdk/testing";
it("sends a welcome email", async () => {
const app = createTestApp({ main: "./main.yaml" });
await welcome("a@pinecart.dev");
mailbox(app).toHaveSent({ to: "a@pinecart.dev", template: "welcome" });
});What MainSDK adds on top
- Fakes enforce the same guarantees as production: a marketing email without an unsubscribe fails in a test too.
- Local drivers never reach production:
MAIN-CHECK-0026stops the build. - Built-in drivers run in your app, with no third-party account; Cedar decides in process with no network round trip.
- Nothing goes to MainSDK Cloud before login and opt-in.
See Testing kit and Test your app.
Limits and notes
- Local drivers arrive with their interfaces: the 0.2 milestone ships local mode for
configfiles,secretslocal,policyCedar andlogterminal; the rest come with 0.3. files: localand the getqr.id driver pass the same conformance suite; whether the local driver counts as the second driver forfilesto be stable is still open.pdf,limits,status,feedback,i18nandgeohave no spec yet, so their options are provisional.ai: localis a fake; it does not run a model on your machine.
Swap to or from it
Move from a local driver to a provider with an environment overlay:
email:
driver: resend # main.env.dev.yaml keeps driver: localFAQ
Can I run the whole app offline? Yes, for interfaces whose local drivers have shipped. mainsdk dev makes no calls to providers and needs no cloud account.
Is Cedar only for development? No. Cedar is the default production engine for access and policy, running in process.
Why does mainsdk check --env prod fail with MAIN-CHECK-0026? An interface still resolves to a local driver in production. Set a real driver in main.env.prod.yaml.
Next
- Testing kit, Permissions and Actions and agent tools
- SQLite, getqr.id and OpenTelemetry
- Test your app and Swap a driver
Open questions
Was this page helpful?