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.