Ottabase is an open-source, edge-native SaaS framework on Cloudflare Workers. It ships as a pnpm + Turborepo monorepo with 60+ packages covering dependency-free auth, OttaORM (fat models on Drizzle + D1), RBAC, row-level security, queues, cron, realtime via Durable Objects, blog/CMS, UI, and more. Batteries included, not a hosted backend-as-a-service.
Billing for your own users ships as PayPort, part of Ottabase Pro, the paid bundle. The framework itself needs none of it.
Solo founders and small teams who want to ship a multi-tenant SaaS quickly without rebuilding auth, tenancy, ORM, and edge plumbing every time. The primary app template is TanStack Router v1 + Vite + React on the front and Cloudflare Workers on the back.
It is not a low-code platform. You write TypeScript, enable packages in config, and control every layer.
Yes. Every package in the repository is MIT licensed. You can inspect, fork, and extend anything in the ecosystem, and nothing in it depends on a paid add-on.
Ottabase Pro is a separate, paid bundle for the parts that keep you running and make you money: PayPort for billing your users, Helpdesk for support, Campaigns and Lifecycle for email, Blackbox for error tracking, Beacon for a status page, Workbench for your database, Privacy for GDPR and CCPA requests, SSO for your customers' identity providers, OG Studio for social cards and Tower for fleet operations, sold as source with repository access as the license. The open-source framework is complete without it.
Yes. Ottabase v1.0.0 is aimed at production SaaS: the stack is TypeScript-first, MIT-licensed, and built on Cloudflare infrastructure that runs at global scale. You still own upstream merges, schema strategy, and how you configure RLS and secrets. That is by design.
Treat upgrades like any serious dependency: read the changelog, run your checks, and pin versions until you are ready to move.
Teams using the full template often land in roughly 4 to 48 hours for a credible MVP: clone, install, pnpm dev, complete the first-run /__bootstrap__ wizard (migrations, RBAC seed, platform owner), then build product screens on top of auto-CRUD and RLS.
Your mileage depends on product complexity. The framework removes most of the repeated SaaS infrastructure work so you spend time on what differentiates your product.
For your own users, yes: PayPort, part of Ottabase Pro. Checkout, provider webhooks, per-user or per-organization licenses with grace, a billing portal, pricing and billing pages; Polar first, provider-generic, with the merchant of record handling tax, invoices and receipts. In the free framework, @ottabase/flags turns a plan into features and limits your routes and UI check, and @ottabase/meter turns usage into credits with a 402 guard.
Without Pro, billing is a normal app concern: auth, organizations, RBAC, flags and meter give Stripe, Paddle or Lemon Squeezy a solid place to hang. @ottabase/premium is the other direction, selling add-ons to other Ottabase apps with licenses verified offline.
You don't install Ottabase from npm - you clone it. Clone github.com/ottabase/ottabase, run pnpm install and pnpm build:pkg, and every @ottabase/* package is wired into the apps through pnpm workspaces. No version skew, no black boxes.
A package is installed by listing its manifest in the app's ottabase/packages.ts, nothing else; pnpm otta add <package> <app> writes that entry, the dependency and the composition file for you. Need another app in the same repo? pnpm otta new web, worker or landing scaffolds one.
Many packages work standalone: UI components, utilities, email templating, and similar. Anything that touches D1, KV, R2, Queues, or Durable Objects assumes a Cloudflare Workers runtime with bindings configured.
Start from the full template when you want the complete SaaS spine (auth, RBAC, RLS, CRUD, queues) without hand-wiring everything from scratch.
OttaORM uses a fat model architecture inspired by Laravel Eloquent. Each model class holds relationships, validation rules, lifecycle hooks, field metadata, and soft delete logic. The business logic lives in the model, not in controllers or service classes.
From any model definition you get a CRUD API auto-generated at /api/ottaorm/{entity} covering GET, POST, PATCH, and DELETE. Calling POST /api/ottaorm/init reads all registered model schemas and creates or alters tables in D1 via Drizzle. Renaming or dropping columns needs a custom migration since those are destructive. Add static admin to a model and it also gets admin screens at /admin/crudhub: list, search, details with related records, forms and row actions.
otta-web (TanStack Router + Vite + Workers) is the primary SaaS app. It has auth flows, multi-tenant org setup, RBAC enforcement, OttaORM, the admin console, and a unified pnpm dev experience. That is where you build your actual product.
otta-worker is the second app shape: one Cloudflare Worker, server-rendered HTML and an API, no SPA and no asset build, on the same package contract. For an internal tool, a webhook receiver, a cron-driven job or a single-purpose API; pnpm otta new worker scaffolds one.
otta-landing (Next.js + OpenNext) is your public landing site. It is a read-only renderer of the same D1: platform admins edit pages, sections, and the theme from the otta-web admin, and visitors get server-rendered pages with no extra backend.
otta-cache is a self-hosted Turborepo remote cache on Cloudflare Workers + R2. One worker serves any number of projects with team-scoped tokens, so CI and every developer share build artifacts without a Vercel account. It sits outside the product runtime: no D1, KV, sessions, or RBAC.
@ottabase/ottaai is a tenant BYOK engine: a user key, then an org key, then the platform default. Keys are encrypted at rest and resolved deterministically, and calls go through Cloudflare AI Gateway, with Unified Billing supported for chat and OpenAI embeddings.
It covers chat with text and image input, text or JSON output, and embeddings. Tasks declare what they need, so a vision or JSON call is refused unless its task allows it. The settings UI ships too.
@ottabase/ui is the Ottabase UI kit: it started as shadcn/ui and is now its own variant, wired to the Ottabase design tokens and providers, with Radix primitives underneath as in shadcn. It also ships the composed pieces apps keep rebuilding: a confirm dialog, a resizable split pane, a JSON editor, status chips and stat tiles.
Other UI packages (Mantine provider, datatable, spotlight, date picker, and so on) compose on top of that stack rather than duplicating every primitive from scratch.
The framework and repo conventions are TypeScript-only: models, Drizzle schema, Workers code, and configs are all typed end to end.
That is what gives you inferred CRUD types, Zod validation at the boundary, and zero drift between API and UI shapes. Plain JavaScript is not a supported first-class path.
Production code targets the Cloudflare Workers runtime (V8 isolates). D1, KV, R2, Queues, Durable Objects, and Workers AI bindings are all first-class citizens.
Locally you run Vite + Wrangler together with pnpm dev. Tooling needs Node.js 24+ and pnpm 10+. The worker process itself is not a Node server.
The first-class story is Cloudflare D1 (SQLite at the edge) with Drizzle and OttaORM on top. KV handles caching, session state, and permission lookups. R2 handles file storage. Analytics Engine handles event tracking.
OttaORM migrations are model-driven: POST /api/ottaorm/init creates and alters tables from your model definitions. Renaming or dropping columns requires a custom migration path.
Three layers, all failing closed. Row-level security scopes every query by organization, user, or app; a model without a policy is refused, and a request whose org membership was not resolved is denied rather than run unscoped. Generic CRUD is an allowlist, so grant, auth, and control-plane tables are never reachable through it.
Authorization is permission + scope, never a role name: platform authority needs a system-scoped platform:admin grant, org authority an org-scoped org:admin grant. Client-supplied org headers only count against your verified memberships.
It is built for them. AGENTS.MD holds the repo rules, .claude/skills holds fifteen task-shaped skills (models, CRUD, forms, RBAC, uploads, email, queues, cron, theming, components, packages, migrations, testing, Cloudflare, updates), and pnpm docs:llms regenerates llms.txt and llms-full.txt from every guide.
The point is consistency: ask an agent for a feature and it registers the model, adds the RLS policy, and uses the generated hooks - the same way you would - instead of inventing a second architecture.
Usually no. For mostly static sites, Astro, Next.js, or plain static hosting is cheaper and simpler.
If the static site sits next to an Ottabase app, use otta-landing: pages and sections live in the same D1 and are edited from the admin, with three themes, drafts, lead forms, sitemaps, and social cards included.
Yes, in the sense that the full SaaS template is designed for Cloudflare Workers, D1, KV, R2, Queues, and Durable Objects. That is where it is tested and documented.
UI and many utility packages can run in any React or bundler setup. The edge-native packages assume Cloudflare bindings are present.
From your machine, pnpm otta deploy <app> is the whole first deploy: it creates the D1, KV, R2 and queue on your Cloudflare account, fills their ids into the config, builds only the packages the app uses, deploys, sets the secrets the app cannot run without, and can bootstrap the database with you as the owner.
After that, connect the app to Cloudflare Workers Builds with pnpm otta deploy <app> --ci as its deploy command, and every push to main ships. GitHub runs the tests on pull requests, keeps a manual deploy as the fallback, and makes PR previews on request. One file per app, cloudflare-config.json, says how it builds and ships, and every path runs the same command.
You develop locally with Wrangler and can run workerd-compatible environments for parity, but the product story is your app on your Cloudflare account, not a traditional VPS stack.
You manage deployments, secrets, schema migrations (the bootstrap wizard once, then Admin → Migrate), and security. There is no separate Ottabase cloud to self-host.
Yes. The framework and all packages are MIT open source with no licensing fee. You pay Cloudflare for usage: Workers free tier covers roughly 100,000 requests per day; D1, KV, R2, and Queues all have generous free tiers.
Most MVPs run at $0 to $5 per month on Cloudflare. As you scale, costs typically stay well under $50 per month. Everything scales with traffic and storage, not seat counts or feature tiers.
You operate your own Cloudflare project. Secrets, RLS rules, upstream merges, and schema decisions are all yours. That freedom is also responsibility.
Support is community-first via GitHub Issues and Discussions. @thinkdj maintains the architecture. There is no bundled enterprise helpdesk.
Yes. The MIT license explicitly allows commercial use, modification, and distribution. Attribution is appreciated but not required.
If Ottabase powers your product and you want to give back, starring the repo, writing about your experience, or sponsoring on GitHub are all welcome.
Ottabase Pro: PayPort (sell plans to your users), Helpdesk (a support inbox), Blackbox (error tracking), Beacon (a status page), Workbench (your database, inside the admin), Privacy (GDPR and CCPA requests, answered on time), SSO (your customers' own identity provider), OG Studio (the card behind every shared link), Campaigns (email and a newsletter to your users), Lifecycle (mail that follows what people do) and Tower (every app you run, on one board), as source, in a private repository you clone into your monorepo. Three yearly licenses, priced by how many people commit: Solo at $149 for one committer, Team at $499 for up to ten, Company at $1,499 for a whole legal entity. The subscription buys access and updates; cancel and every line you pulled stays yours. No license keys, nothing gated.
Nothing already open source ever moves there. See ottabase.com/pro.
Still have questions? Open a discussion on GitHub or join us on Discord.