One npm install. Full SaaS backend.
React hooks for the frontend. Server functions for the backend. Auth, billing, credits, quotas, workspaces, permissions, notifications, and 13 pre-built settings screens. TypeScript-first with full type safety.
Northwind's Workspace
DT4SGLmQh75SAQL
Your app is an organization in BuildBase. Your users sign in and work inside workspaces - one per team or customer.
You set up
In the console and the SDK
- One npm install and a provider around your app
- Hooks and components where your app needs them
- The server SDK in your backend
You get
For you and your team
- Settings screens for workspaces, members and billing, already built
- TypeScript types for everything the SDK returns
- Every screen in 8 languages, including right-to-left
Three entry points, one package
Import what you need. React SDK for the frontend, server SDK for the backend, data module for reference data.
React SDK
/react
40+ hooks, 20+ conditional components, 13 pre-built settings screens. Add a provider, call hooks, ship. Works with Next.js, Vite, React Router / Remix, TanStack Start, or any other React web app.
- useSaaSAuth() - sign in, sign out, session
- useSaaSWorkspaces() - CRUD, members, roles
- useSubscription() - plans, checkout, trials
- useCreditBalance() - consume, purchase, track
- useQuotaUsageStatus() - record, enforce limits
- usePermissions() - 3-tier permission gates
- useTrialStatus() - days remaining, ending?
- useSeatStatus() - seat limits, invite checks
- useTranslation() - i18n, RTL, native numerals
- usePushNotifications() - subscribe, permission
Server SDK
@buildbase/sdk
Framework-agnostic. Works with Next.js API routes and Express, NestJS, Fastify, Hono, Astro, on Node.js, Bun, Deno and Cloudflare Workers. Factory pattern with automatic session resolution.
- bb.usage.record() - metered billing
- bb.usage.recordBatch() - bulk (up to 100)
- bb.credits.consume() - with idempotency
- bb.subscription.get() - check plan status
- bb.subscription.checkout() - Stripe session
- bb.workspace.list/create/update/delete()
- bb.users.invite() - add workspace member
- bb.notification.send() - email + push
- bb.permissions.check() - verify access
- bb.withSession() - background jobs
Shared
/data + core exports
Reference data, billing utilities, permission constants, and150+ TypeScript types shared across frontend and backend. Zero React dependency.
- countries, currencies, languages, timezones
- formatCents() - locale-aware currency
- getPricingVariant() - multi-currency plans
- calculateTotalSubscriptionCents()
- validateInvite() - seat limit checks
- Permission.* - 13 platform permissions
- resolvePermissions() - 3-tier resolution
- verifyWebhookSignature() - HMAC-SHA256
- parseWebhookEvent() - typed payloads
- eventEmitter - cross-component events
Production code, not pseudocode
Every example runs as-is. Copy, paste, ship.
Add the provider
Add the provider to the root layout. Pass the org ID and auth config. The SDK handles session management, token refresh, workspace loading, and settings resolution automatically.
import { ApiVersion } from '@buildbase/sdk';
import { SaaSOSProvider } from '@buildbase/sdk/react';
export default function Providers({ children }) {
return (
<SaaSOSProvider
serverUrl="https://api.yourapp.com"
version={ApiVersion.V1}
orgId="your-org-id"
auth={{
clientId: 'your-client-id',
redirectUrl: 'http://localhost:3000',
}}
locale="en" // en, es, fr, de, ja, zh, hi, ar
>
{children}
</SaaSOSProvider>
);
}Sign in, sign out
One hook returns the user, auth status, sign in, sign out, and openWorkspaceSettings() to open any settings screen. Conditional components render based on auth state.
import {
useSaaSAuth,
WhenAuthenticated,
WhenUnauthenticated,
} from '@buildbase/sdk/react';
function App() {
const { user, signIn, signOut, openWorkspaceSettings } = useSaaSAuth();
return (
<>
<WhenUnauthenticated>
<button onClick={() => signIn()}>Sign In</button>
</WhenUnauthenticated>
<WhenAuthenticated>
<p>Welcome, {user?.name}</p>
<button onClick={() => openWorkspaceSettings('subscription')}>
Manage Plan
</button>
<button onClick={signOut}>Sign Out</button>
</WhenAuthenticated>
</>
);
}Paywalls as components
useTrialStatus() returns days remaining and whether the trial is ending. Conditional components gate UI by subscription state, specific plans, or trial status. Checkout creates a Stripe session automatically.
import {
useSubscription,
useTrialStatus,
useCreateCheckoutSession,
WhenTrialEnding,
WhenNoSubscription,
WhenSubscriptionToPlans,
} from '@buildbase/sdk/react';
function BillingPage({ workspaceId }) {
const { subscription } = useSubscription(workspaceId);
const { isTrialing, daysRemaining } = useTrialStatus();
const { createCheckoutSession } = useCreateCheckoutSession(workspaceId);
return (
<>
<WhenTrialEnding daysThreshold={3}>
<Banner>{daysRemaining} days left in your trial.</Banner>
</WhenTrialEnding>
<WhenNoSubscription>
<button onClick={() => createCheckoutSession({
planVersionId: 'pro-v1',
billingInterval: 'monthly',
})}>
Subscribe to Pro
</button>
</WhenNoSubscription>
<WhenSubscriptionToPlans plans={['starter']}>
<UpgradePrompt />
</WhenSubscriptionToPlans>
</>
);
}Consume, track, gate
Consume credits with idempotency keys for safe retries. Returns a typed INSUFFICIENT_CREDITS error on 402 with available and requested fields. Track expiring credits with a configurable lookahead window (1-90 days).
import {
useCreditBalance,
useConsumeCredits,
useExpiringCredits,
WhenCreditsExhausted,
WhenCreditsLow,
} from '@buildbase/sdk/react';
function AIFeature({ workspaceId }) {
const { balance } = useCreditBalance(workspaceId);
const { consumeCredits } = useConsumeCredits(workspaceId);
const { expiringCredits } = useExpiringCredits(workspaceId, 7);
const handleGenerate = async () => {
try {
await consumeCredits({ amount: 10, description: 'AI generation' });
// proceed with generation
} catch (err) {
if (err.code === 'INSUFFICIENT_CREDITS') {
// err.available and err.requested are available
}
}
};
return (
<>
<p>Credits: {balance?.available}</p>
{expiringCredits > 0 && <p>{expiringCredits} credits expire soon</p>}
<WhenCreditsLow threshold={10}>
<p>Running low — buy more credits.</p>
</WhenCreditsLow>
<WhenCreditsExhausted>
<p>No credits left.</p>
</WhenCreditsExhausted>
<button onClick={handleGenerate}>Generate (10 credits)</button>
</>
);
}Backend integration
The BuildBase() factory resolves sessions automatically from a callback. For background jobs or non-request contexts, use withSession() to create a scoped client. Supports configurable timeout, retry with exponential backoff, and debug logging.
import BuildBase from '@buildbase/sdk';
const bb = BuildBase({
serverUrl: 'https://api.yourapp.com',
orgId: 'your-org-id',
getSessionId: async () => {
const cookies = await getCookies();
return cookies.get('bb-session')?.value ?? null;
},
});
// API route — record usage and enforce quota
export async function POST(req) {
const usage = await bb.usage.record(workspaceId, {
quotaSlug: 'api-calls',
quantity: 1,
idempotencyKey: req.headers.get('x-request-id'),
});
if (usage.available <= 0) {
return Response.json({ error: 'Quota exceeded' }, { status: 429 });
}
return Response.json({ remaining: usage.available });
}
// Background job — use withSession() for non-request contexts
const api = bb.withSession(serviceAccountSessionId);
await api.credits.consume(workspaceId, { amount: 50 });
await api.notification.send(workspaceId, 'job-completed');Verify and handle
HMAC-SHA256 signature verification with timing-safe comparison and configurable max age (default 5 minutes). Parse events into typed payloads. Handle subscription changes, credit events, workspace actions, and more.
import { parseWebhookEvent } from '@buildbase/sdk';
export async function POST(req) {
const body = await req.text();
// Verifies the signature and parses the payload — returns null on failure
const parsed = parseWebhookEvent({
body,
signature: req.headers.get('x-buildbase-signature'),
timestamp: req.headers.get('x-buildbase-timestamp'),
secret: process.env.WEBHOOK_SECRET,
});
if (!parsed) {
return Response.json({ error: 'Invalid signature' }, { status: 401 });
}
switch (parsed.event) {
case 'subscription.upgraded':
await enablePremiumFeatures(parsed.data.workspaceId);
break;
case 'credit.low_balance':
await notifyTeam(parsed.data.workspaceId);
break;
case 'workspace.member_added':
await syncToExternalCRM(parsed.data);
break;
}
return Response.json({ received: true });
}3-tier permission resolution
Permissions resolve through three layers: workspace overrides, then org settings, then SDK defaults. Owners get all permissions automatically. useSeatStatus() returns member count, included seats, billable seats, max-seat status, and an invite validation result with a human-readable block reason.
import {
usePermissions,
useSaaSAuth,
useSeatStatus,
WhenPermission,
WhenWorkspaceRoles,
Permission,
} from '@buildbase/sdk/react';
function TeamPage({ workspace }) {
const { can } = usePermissions();
const { openWorkspaceSettings } = useSaaSAuth();
const {
memberCount, includedSeats, availableSeats,
isAtMax, canInvite, inviteBlockReason,
} = useSeatStatus(workspace);
return (
<>
<p>{memberCount} of {includedSeats} seats used</p>
<WhenPermission permission={Permission.WORKSPACE_MEMBERS_INVITE}>
<button disabled={!canInvite}>
{canInvite ? 'Invite Member' : inviteBlockReason}
</button>
</WhenPermission>
<WhenWorkspaceRoles roles={['owner', 'admin']}>
<button onClick={() => openWorkspaceSettings('permissions')}>
Manage Permissions
</button>
</WhenWorkspaceRoles>
{can(Permission.WORKSPACE_BILLING_MANAGE) && <BillingLink />}
</>
);
}8 languages, native numerals
600+ translated strings across all settings screens. ICU MessageFormat for pluralization. Native numeral systems: Devanagari for Hindi, Arabic-Indic for Arabic. RTL layout direction for Arabic. English bundled by default; other languages lazy-loaded.
import { useTranslation, SUPPORTED_LOCALES } from '@buildbase/sdk/react';
// Locales: 'en', 'es', 'fr', 'de', 'ja', 'zh', 'hi', 'ar'
function PriceDisplay({ cents, currency }) {
const { t, fmtCents, fmtNum, dir } = useTranslation();
return (
<div dir={dir}> {/* Automatically 'rtl' for Arabic */}
<p>{t('subscription.currentPlan')}</p>
<p>{fmtCents(cents, currency)}</p>
{/* $49.99 (en) | ४९.९९ (hi, Devanagari) | ٤٩٫٩٩ (ar, Arabic-Indic) */}
<p>{fmtNum(1234)}</p>
{/* 1,234 (en) | १,२३४ (hi) | ١٬٢٣٤ (ar) */}
</div>
);
}13 pre-built settings screens
Every SaaS needs workspace settings. The SDK ships a production-ready settings dialog opened with one function call. Translated, permission-gated, and responsive.
openWorkspaceSettings('subscription')Edit name, email, language, country, currency, and timezone
Manage passkeys and review or sign out active sessions
Review signed-in devices, rename them, sign out, or forget unrecognized ones
Review AI agents with account access and disconnect them to revoke access
Set workspace name, icon, and billing currency
Invite members by email, assign roles, track seat usage, remove access
View current plan, switch plans, cancel or resume, access invoices
Track per-quota usage, overage costs, and billing cycle
Check balance, purchase packages, review transaction history
Enable or disable feature flags per workspace
Subscribe to push notifications, toggle per-event email and push delivery
Edit role-permission matrix with granular toggle controls
Permanently delete workspace with confirmation
<PricingPage>, <CreditStorePage>, <WorkspaceSwitcher>, and <BetaForm> - all with render props for full layout control.Declarative UI gating
No if-statements for permissions, subscriptions, or feature flags. Wrap UI in conditional components. The SDK resolves state and renders or hides children.
Auth
Subscriptions
Quotas
Credits
Permissions & Roles
Feature Flags
Also included
8 languages built in
English, Spanish, French, German, Japanese, Chinese, Hindi, Arabic. ICU MessageFormat with pluralization. RTL for Arabic. Lazy-loaded - only English in the initial bundle.
Multi-currency billing
Per-plan pricing variants by currency. formatCents() for locale-aware display. Workspace billing currency lock. Available currencies auto-detected from plan config.
Notifications
Send email and push notifications from the server SDK. Per-event user preferences with toggles. Browser push with VAPID auto-setup. Browser-specific unblock instructions.
Seat-based pricing
useSeatStatus() calculates included seats, billable extras, per-seat cost, invite eligibility, and human-readable block reasons. Syncs with subscription state.
Pricing utilities
calculateTotalSubscriptionCents(), getBasePriceCents(), getQuotaOverageCents(), getBillingIntervalAndCurrencyFromPriceId() - full pricing math without Stripe SDK.
Usage batch recording
bb.usage.recordBatch() sends up to 100 usage events in one call. Idempotency keys per item. Returns per-item success/failure results.
Event system
Global eventEmitter for cross-component communication. Workspace CRUD, user changes, and role updates emit typed events components can subscribe to.
Auth intent preservation
saveAuthIntent() stores the destination before auth redirect. consumeAuthIntent() restores it after sign-in. Survives full page reloads.
40+
React Hooks
20+
Conditional Components
13
Settings Screens
150+
TypeScript Types
8
Languages
Skip the blank file
Start from a Next.js app that already has the SDK wired in, or have Claude add it to yours.
Integrate the SDK with Claude
buildbase@buildbase-skills
Takes a Next.js app from npm install to a working sign-in, then covers workspaces, billing, feature flags, quotas, credits, notifications, webhooks and calling BuildBase from a non-Node backend.
In Claude Code:
Any agent (Cursor, Codex, Copilot and others), from a shell:
Then ask Claude: “Add BuildBase auth to my Next.js app.”
Other ways to install, including claude.aiNext.js starter
buildbase-app/nextjs-starter
A Next.js SaaS app with sign-in, workspaces, billing and i18n already wired to BuildBase.
Agent + MCP starter
buildbase-app/nextjs-agent-mcp-starter
An agent-first Next.js app: a live MCP server with agent OAuth, from one config.
Examples
buildbase-app/examples
Working apps on BuildBase, most of them popular open-source templates with auth, teams or billing swapped in. Each has a Deploy button.
SDK source
buildbase-app/sdk
The source and changelog of @buildbase/sdk.
Frequently Asked Questions
Do my users see this?
They see the workspace settings, profile, billing and credits screens the SDK renders in your app. Sign-in happens on hosted pages with your branding.
Which frameworks does it work with?
React on the front end (Next.js, Vite, React Router / Remix, TanStack Start), and Node.js on the server (Express, NestJS, Fastify, Hono, Astro).
What do I install?
One package, @buildbase/sdk. The React parts come from @buildbase/sdk/react, and the server functions from @buildbase/sdk itself.
Which languages do the screens come in?
8: English, Spanish, French, German, Japanese, Chinese, Hindi, Arabic, including right-to-left.