Blocks
Blocks are production features you add with one command. Like shadcn/ui components, they are copied into your project as source code: you read them, own them and change them. There is no runtime package to keep up with.
npx calm add jobs Blocks
+ @calmapi/jobs v1.0.0 · @calmapi (bundled)
Background jobs and cron on MongoDB (no Redis): retries with backoff, schedules, event triggers, admin API and a devtools panel.
Files
create app/blocks/jobs/cron.js
create app/blocks/jobs/index.js
create app/blocks/jobs/queue.js
create app/jobs/welcome-email.js
Environment (.env.example and .env)
+ JOBS_WORKER=on
+ JOBS_CONCURRENCY=4
? Apply these changes? [Y/n]calm add writes the files, adds npm dependencies to package.json and installs them, appends environment variables to .env.example and .env (without touching values you already have), records the block in calm.lock, and prints the block's notes. Restart (or let npm run dev restart) and the block is live: every folder in app/blocks/ with an index.js is loaded at boot.
Official blocks#
| Block | What you get |
|---|---|
| Users and access | |
| api-keys | Personal and service API keys with scopes, hashed at rest, expiry and revoke |
| magic-link | Passwordless sign-in by email, bound to the browser that asked |
| totp | Two-factor authentication with authenticator apps, recovery codes and replay protection |
| privacy | Users export their data and delete their account (delete, anonymize or keep per resource) |
| Messaging | |
| notifications | ctx.notify(): in-app inbox, push and email in one call, with preferences and quiet hours |
| push-expo / push-fcm | Push notification delivery through Expo or Firebase Cloud Messaging, alone or together |
| mail-resend / mail-smtp | Email delivery |
| webhooks | Outgoing webhooks for resource events: signed, retried, logged, SSRF safe |
| realtime-sse | Live resource events, filtered per subscriber by the same policies |
| Data and files | |
| storage-local | Uploads to disk with type and size allowlists, magic-byte checks and safe downloads |
| storage-s3 | Direct-to-S3 uploads with presigned URLs (AWS S3, Cloudflare R2, MinIO) |
| audit-log | Who changed what, with field diffs (private values never logged) |
| soft-delete | softDelete: true per resource, with trash and restore |
| Running in production | |
| jobs | MongoDB job queue and cron (no Redis): retries, schedules, event triggers, admin API |
| feature-flags | Kill switches, gradual rollouts, targeting, variants and route gates |
| idempotency | The Idempotency-Key header: safe retries for payments and other writes |
| rate-limit-mongo | Rate limits shared across instances |
| APIs and agents | |
| api-docs | Interactive API reference at /docs |
| mcp-server | Your resources as MCP tools for AI agents, enforced by your API's rules |
npx calm add --list # official blocks
npx calm add jobs audit-log # several at once
npx calm add jobs --dry-run # show the plan, write nothing
npx calm block list # blocks in this project, and the files you changedThe devtools Blocks panel shows every installed block: where it came from, the files you changed since, what it hooks into, its environment variables (set or missing) and its routes.
Where blocks come from#
An address is resolved like this:
| Address | Source |
|---|---|
jobs or @calmapi/jobs | The official registry. The CLI carries a copy of it, so this works offline. --remote fetches https://docs.calmapi.dev/r/jobs.json instead. |
gh:acme/blocks/billing | r/billing.json in a GitHub repository, what calm block pack writes. Add @v1.2.0 (or a branch or commit) to pin it. |
@acme/billing | The @acme registry declared in your package.json |
https://example.com/r/thing.json | Any URL |
./blocks/thing.json | A local file |
Registries are declared in package.json:
{
"calm": {
"registries": { "@acme": "https://acme.dev/r/{name}.json" }
}
}The official registry is served as JSON at https://docs.calmapi.dev/r/index.json, one file per block (for example /r/jobs.json), in the shadcn registry-item format. To write and share your own, see Building your own block and Publishing your own block.
Safety rules#
- A block can only write inside your project, never to
calm/orcalm.lock. - Existing files with different content are kept and reported as conflicts; pass
--overwriteto replace them. - Blocks that provide the same resource refuse to be installed together (
storage-localandstorage-s3both providefile). registryDependenciesare installed first; dependencies already inpackage.jsonare left as they are.- Blocks can declare the oldest CalmAPI they work with (
minVersion); older projects are asked to runcalm upgradefirst. - Blocks that are not official are reviewed before anything is written:
calm addlists in plain language what their code does (network requests, file writes, child processes,eval, request hooks, the environment variables it reads, the hosts it mentions). Risky findings must be confirmed, and with--yesthey also need--trust. A block runs in your app with full access, like any code you paste, so read it. See What people see before installing.
After adding a block#
The block's code is now in your project, and it is yours. Change it, delete parts you do not need, or remove the block by deleting its folder (and its entry in calm.lock). Re-running calm add <block> later shows which files differ from the current upstream version. calm upgrade never touches block files.