Pricing
Pluralize charges the developer (you) per platform usage, not per app and not per end-user tenant. One subscription, one set of caps, all your apps share it. Tenants inside your apps pay you (via the billing flow) — that money flows to your Stripe account, Pluralize takes a flat 5% application fee.
Plans
| Plan | Price | Tenants (total) | Records storage | File storage | API requests / mo | Emails / mo | |---|---:|---:|---:|---:|---:|---:| | Hobby | Free | 100 | 100 MB | 1 GB | 50,000 | 500 | | Starter | $19 / mo | 1,000 | 2 GB | 20 GB | 500,000 | 5,000 | | Pro | $79 / mo | 10,000 | 20 GB | 200 GB | 5,000,000 | 50,000 | | Scale | Talk to us | Unlimited | Unlimited | Unlimited | Unlimited | Unlimited |
Every developer starts on Hobby. Upgrade at any time from Dashboard → Billing. Downgrades take effect at the end of the current period; if you're already over the new plan's cap when you downgrade, signups and writes stop until you're back under it (read paths keep working).
What each cap means
| Cap | Counted as | Resets |
|---|---|---|
| Tenants | Sum of tenants.count across all your apps where deleted_at IS NULL. | Never (lifetime). |
| Records storage | pg_column_size(records.data) summed across every collection in every app. | Never (lifetime). |
| File storage | files.size_bytes summed across all apps. | Never; deleted files free up bytes immediately. |
| API requests | Every successful response from /api/v1/* (excludes 4xx errors and OPTIONS preflights). | Calendar month, UTC. |
| Emails | Every transactional email sent — verify-email, password-reset. | Calendar month, UTC. |
What happens at the cap
Pluralize fails closed on writes and open on reads. The whole point is to give you a hard stop before a runaway tenant or a viral moment turns into a surprise bill.
| Cap reached | Endpoints affected | HTTP response |
|---|---|---|
| Tenants | POST /api/v1/auth/signup | 402 quota_exceeded with { metric: 'tenants', limit, current } |
| Records bytes | POST /api/v1/data/<collection> (insert) and PATCH (update if larger) | 402 quota_exceeded with { metric: 'records_bytes', ... } |
| File bytes | POST /api/v1/files | 402 quota_exceeded with { metric: 'blob_bytes', ... } |
| Requests / mo | Every /api/v1/* endpoint | 402 quota_exceeded with { metric: 'reqs', resetsAt } |
| Emails / mo | Verify-email + password-reset | The email is silently skipped — the underlying operation (signup / reset request) still succeeds; the user just won't get the mail. The skip is logged on the server. |
The 402 quota_exceeded body always includes the metric name, the cap value, and your
current usage. Surface a friendly upgrade prompt in your UI when you see this code.
import { PluralizeError } from '@pluralize/sdk';
try {
await app.auth.signup(email, password);
} catch (err) {
if (err instanceof PluralizeError && err.code === 'quota_exceeded') {
return showUpgradeBanner();
}
throw err;
}Watching usage
Dashboard → Billing shows current usage vs
cap for all five metrics with colour bars. The page reads from
GET /api/v1/developer/usage; you can hit the same endpoint from a script if you want
to plot it elsewhere.
Auto-pause for dormant apps
Apps with no /api/v1/* traffic for 30 consecutive days are paused automatically by
a daily cron. A paused app returns 402 app_paused from every endpoint until you
reactivate it from the dashboard. This protects developers from forgetting about a
prototype that someone scripts a bot against. Reactivation is one click.
What you do NOT pay Pluralize for
- The Stripe transaction fees on subscriptions your tenants buy from you. Stripe charges those directly to your account.
- Your own infrastructure (Vercel, your DB, your CDN). Pluralize doesn't proxy your domain data — only auth and billing flow through us.
- Custom plan logic. Defining your tenant-facing tiers (free, pro, etc.) is part of the platform — there's no per-plan or per-active-subscription fee from Pluralize.