Skip to content

Release history

What's happening inOttabase.

Every release, every feature, every fix. Follow along as the stack evolves.

Minor
1.12.0

One deploy, from a terminal, Cloudflare Workers Builds and GitHub

  • otta deploy is the one deploy. From a terminal it is the whole first deployThe D1, KV, R2 and queue, their ids filled in, the build, the deploy, the secrets and the bootstrap. In Cloudflare Workers Builds and GitHub Actions it is the same command with --ci: nothing created, no secret touched, every missing value named before anything builds.
  • Cloudflare Workers Builds is the way to ship every push.GitHub runs the tests on pull requests and keeps a manual deploy and PR previews, all running otta deploy instead of their own scripts.
  • One file per app says how it shipscloudflare-config.json, read strictly, so a typo stops the deploy and names itself instead of changing how the app ships. Only the workspace packages an app uses are built.
  • Only what changed deploys--watch-paths prints an app's build watch paths in Workers Builds' own syntax (the app, every workspace package it reaches, the root build files), --changed-since deploys from a diff, and #skipdeploy in a commit message skips a deploy anywhere.
  • PR previews are their own Workers on the preview resources, removed when the PR closes; a manual preview follows its branch and goes when the branch is deleted. Deploys run in GitHub Environments, so a reviewer can approve a PR before its code sees a secret.
  • Safer by defaultVersion URLs are off for every app, the CI secrets never reach a build script (only the names an app asks for in requiresSecrets do), a health check gives up after ten seconds, and a new app gets its own private files and backups buckets.
  • Ottabase ProBlackbox's source map upload gets its token through requiresSecrets, and the demo builds with otta deploy --config-only.
3 breaking changes
  • cloudflare-config.json drops workerName, outputDirectory, assetsDirectory and customBuildSteps, an unknown key stops the deploy, and every app Cloudflare deploys needs one.
  • The APPS_TO_DEPLOY and CF_WORKER_SUBDOMAIN secrets are gone: deployable in each app's manifest decides what CI ships, and deploy.yml is manual.
  • An app's deploy script runs otta deploy, and .github/scripts (the secret substitution and app discovery scripts) is gone.
Minor
1.11.0

A bot check on every public form, one files system, and images at the size the screen needs

  • A bot check on every public formTurnstile, Cloudflare's free check, guards sign-in, the magic link, register, password reset, verification resend, protected post unlock, guest comments and the landing lead form. Most people never see it. It stays off until both keys are set, and System readiness shows them.
  • Guest commentsA signed-out visitor comments with a name and an optional email after the bot check. Their comment starts pending and waits in Admin, Content, Comments for a moderator to approve, hide or delete.
  • One files system, three buckets by who may readPublic, private and backups. A file's type is read from its contents, photos lose their EXIF and GPS before they are stored, WebP variants are made at upload, and each organization has a quota. Private files open only for their audience or through a signed link, and a quarantined public file has its URLs purged.
  • Images at the size the screen needsContent keeps the stored file, never a URL, and the blog, landing pages, editor blocks, menus and the media library all render it with srcset. Changing R2_PUBLIC_URL moves every image at once.
Show 4 more
  • A block kit for the editorAn Edit / Preview switch with the preview drawn by the real renderer, a block palette and an inline spoiler (Ctrl+Shift+H). OttaRenderer is its own renderer now, with no third-party renderer and an allowlist inline parser that runs in Workers too.
  • Smaller thingsEvery due cron task runs in its own invocation, the bus carries user.created, user.verified and lead.created, and the image cropper is rebuilt around a fixed frame: pan, pinch, zoom, rotate, straighten and flip underneath it.
  • HardeningBackups and private files can no longer be fetched by URL, secrets are compared in constant time, rate limiters with a missing binding are closed in production, protected post unlock is rate limited, and the auth mails go out once per address per minute.
  • Ottabase Prootta add pro installs it into an app, the newsletter and status page subscribe forms get the bot check, and the demo becomes one shared Pro instance that resets itself every hour.
3 breaking changes
  • Image fields hold a FileSource (a stored file, or an outside URL as a string) across editor blocks, the blog and landing pages; the old url, mediaId, thumbnailUrl, previewUrl, width and height fields are gone, and landing fields drop their Url suffix.
  • Media rows are records, not URLs: media drops provider, url, thumbnailUrl, previewUrl and isPublic. Files live in three buckets, OBCF_R2, OBCF_R2_PRIVATE and OBCF_R2_VAULT.
  • /api/ottaorm/init takes MIGRATION_SECRET from a Bearer header or the JSON body only, never ?secret=.
Minor
1.10.0

CrudHub, a query builder, and every user's own language and timezone

  • CrudHubAny model that adds static admin gets admin screens at /admin/crudhub. A directory by package, server search, a column menu, typed empty values, row actions run on the server, related records on the details page, and forms that ask before you leave unsaved changes. Grant and auth tables never appear.
  • A chainable query builderPost.query().where(...).whereContains(...).orWhere(...).with('tags.category:id{name}').paginate(). It compiles to the same safe where objects, with new not-in, null and escaped LIKE operators, nested eager loading, and attachPivot, detachPivot and syncPivot for many-to-many rows.
  • Every user has a language and a timezone, filled from the browser on sign-up.Tables, forms and detail pages show dates in them, and the profile has a Language and region card with a live preview.
  • A sessions pageEvery signed-in device with its browser, city and masked IP, renamed inline, revoked one by one or all at once. A revoked device lands on the login page saying why.
Show 3 more
  • System readiness on /adminEvery setting, binding and health check each package declares, with a red banner for anything missing, a copyable wrangler command for a missing secret, and the build that is running. Deploys are tagged with the commit.
  • URL noticesA redirect carries a code such as ?notice=email-verified, never text. The app shows it once and takes it off the URL, and packages declare their own codes.
  • Ottabase ProSSO errors become notices and new SSO accounts start in the browser's language, Privacy covers data kept outside the database, Tower shows the build each app runs.
3 breaking changes
  • Redirects use ?notice=<code> instead of ?verified=1, ?passwordChanged=1 and ?error=<Code>; auth failures are auth.<code> (auth.oauth-signin and so on).
  • Package env declarations take objects ({ key, description, secret, kind }) next to plain names, and PackageRegistry gains envDeclarations(). A plain name now counts as a secret on the readiness page.
  • Post's passwordHash is hidden by the model class, and posts, comments, media and organizations are read-only in CrudHub.
Minor
1.9.0

Alerts, a lean starter, and free Vault and Webhooks

  • New @ottabase/alertsOne raise() for every package, to email, Slack, Discord, Telegram, PagerDuty or a signed webhook, routed by severity, with cooldowns, hourly limits, daily digests and retries. A 5xx, a failed cron task or a queue job out of retries becomes an alert on its own.
  • The lean starterotta new web my-app --minimal (or --preset blog, --preset saas) scaffolds the app with only what the preset keeps. otta strip removes a package or the demo, and otta deploy makes a first deploy straight to Cloudflare, resources, secrets and bootstrap included.
  • New @ottabase/ogThe 1200 by 630 card behind a shared link, drawn by Browser Rendering in the brand's colors, kept in R2 and served from a URL the app signs. Blog posts without a hero image get one.
  • Vault and Webhooks are free packages, with no license and nothing gated.Vault backs up the R2 bucket beside the tables, each file once per version, and limits how many manual backups exist and how often. Webhooks caps endpoints per workspace and prunes its delivery log nightly.
Show 3 more
  • New @ottabase/contextThe otta-context schema, version 2, in one package with no dependencies. Discover serves it with an ETag, keeps an owner copy behind a key, and reads the brand off the theme.
  • Charts gain treemap, radar, waterfall and scatter, and every chart draws 50,000 rows and more.
  • Ottabase Pro adds SSO (OpenID Connect sign-in by email domain, with SCIM) and OG Studio (a visual editor for the social card). otta pro update my-app pulls a Pro release and wires what is new.
2 breaking changes
  • @ottabase/notifications no longer has a system channel (SystemChannel, notifySystem, the system_notifications table): operator alerts are @ottabase/alerts.
  • @ottabase/webhooks takes a required appId for the nightly prune and drops its license options. A wrangler migration deletes the WebhookEndpointQuota Durable Object.
Minor
1.8.0

Packages as a platform, and Ottabase Pro

  • New @ottabase/kernelOne manifest declares a package's tables, migrations, models, RLS policies, routes, cron, queue jobs, events, nav, env and health. An app installs a package by listing it, and the registry throws at boot on any clash.
  • pnpm otta add wires a package, or a whole bundle, into an appMigrations, routes, admin pages, SPA routes and an error reporter. Safe to re-run. A second app shape, otta-worker, is one server-rendered Worker with no SPA.
  • Nine more free packagesEvents (a typed bus with queue fan-out), flags (plans, features, limits, 402 guards), meter (usage credits in one conditional UPDATE), apikeys, postmaster (inbound mail, suppression, one-click unsubscribe, bounce webhooks), vault (backups to R2, restore, per-tenant export), fleet (the beacon that makes an app watchable), legal, screenshot, plus Vectorize, Workers AI, Browser Rendering and Workflows wrappers in cf.
  • Design System v1 everywhereVerdant ramp, cool neutrals, Inter, one six-tone status language. The admin, the operator Worker pages, the bootstrap wizard and the otta CLI share the tokens and the words.
Show 4 more
  • One UI kit, @ottabase/uiRadix primitives on the design tokens, now with Timeline, TreeView, AvatarGroup, Rating and VisuallyHidden. OttaSelect gets OttaTagsInput and a "Create" row.
  • New @ottabase/chartszero-dependency SVG charts drawn to the Design System chart spec. Line, area, bar, combo, donut, funnel, sankey, heatmaps, tracker and more on a headless geometry engine that also runs in a Worker.
  • Ottabase ProSeven paid packages (PayPort, Helpdesk, Blackbox, Beacon, Workbench, Privacy, Tower) sold as source on three yearly licenses. otta add pro installs them with nothing left to wire.
  • otta-web runs as a public demo (DEMO_MODE), tours the Pro packages, and splits navigation by audience: an account menu for users, growth tools under /admin. Every user gets a referral link at /r/{username}. Discover is AI-readable by default.
3 breaking changes
  • @ottabase/ui-shadcn is now @ottabase/ui and absorbs ui-components, ui-split-pane and ui-base. ShadcnProviders is UIProviders.
  • Tailwind CSS v4, configured in CSS: no tailwind.config and no JavaScript preset; apps list what to scan with @source. @tailwindcss/forms is dropped.
  • @ottabase/premium-webhooks is now @ottabase/webhooks. The hand-wired config.migrations.ts, config.routes.ts and config.premium.ts are gone, and so are the OTTABASE_PKG_* toggles: a package is installed when it is listed.
Minor
1.7.0

Landing sites, edited in the admin

  • New @ottabase/ottalandingThe public landing site lives in D1. Typed sections (hero, logos, features, testimonials, pricing, FAQ, CTA, text, contact, signup) are declared once as field descriptors that derive the TypeScript type, the shared Zod validation, and the admin form.
  • Three themes - Launch, Editorial, Bold - each a Brand Engine preset plus its own layout.Switching theme never touches content, and every theme ships a visitor light/dark switch applied before paint.
  • Platform admins edit at /admin/content/landingTheme picker with live previews, page editor with reorder and field-level errors, shareable draft previews, media-library images, logo, favicon, and brand color.
  • Contact and signup sections feed an admin inbox with email digests.Social cards, sitemap, and robots.txt are generated; only production is indexable.
Show 4 more
  • apps/otta-landing is now a read-only renderer of the same D1, server-rendering theme tokens on first paint with exactly one <h1> per page.
  • RLS denies any org-scoped operation whose context has no resolved membership instead of skipping the check, and a tenant-isolation suite drives the real security context into the real RLS engine.
  • Audit logs get retentionA seeded daily audit:prune task (90 days by default) you can edit or pause in the Cron admin. Queue dead letters are keyed by job id, so lookup, retry, and delete are one KV read.
  • Pre-launch cleanupbackward-compatibility shims are removed across ottablog, brand-engine, ottalayout, utils, and otta-web, and the Worker type-checks pass without the DOM lib.
2 breaking changes
  • The landing app’s slot/variant configurator, per-visitor localStorage choices, and config/brand.config.ts are removed, and the empty @ottabase/homepage-contract package is gone. Content comes from the admin.
  • OAuth provider access, refresh, and id tokens are no longer stored - accounts is an identity link only. Auth.js-era session and authenticator tables are removed.
Minor
1.6.0

Fail-closed everywhere

  • RBAC role grants are scoped to an organization and fail closed.OttaORM unifies its migrations and closes remaining RLS gaps.
  • Security sweepInterstitial URLs, raw HTML blocks, and data-table link/image cells are sanitized; analytics is admin-only; audit trails record what actually happened; brand writes are validated.
  • OttaAI takes image input and returns JSON, with route-aware key resolution, per-task output budgets, and a /api/ai/vision route. Cloudflare Unified Billing covers chat and OpenAI embeddings.
  • OttaBlog gains author archives and JSON/Markdown import and export.The media library gets a draggable, immersive gallery with solid gesture handling.
Show 1 more
  • Test, coverage, and CI gates now run per package, so a package without tests can no longer pass silently.
Minor
1.5.0

Agent-ready repo, multilingual blog

  • Fourteen repo-specific agent skills in .claude/skills (models, CRUD, forms, RBAC, uploads, email, queues, cron, theming, components, packages, migrations, testing, Cloudflare) encode the Ottabase way so agents stop inventing alternate architectures.
  • llms.txt and llms-full.txt are generated from the docs with pnpm docs:llms.Every package README now documents accessibility, SSR, and performance.
  • OttaBlog goes multilingualper-blog language policies, translations with protected edits, and localized slugs that resolve directly. Date archives, fuzzy original dates, and a one-button share popover land too.
Minor
1.4.0

Self-hosted Turborepo remote cache

  • New otta-cache appA Turborepo remote cache (v8 artifact API) on Cloudflare Workers + R2. Artifacts are namespaced per team in one bucket; tokens are scoped to teams and to read or read-write.
  • CI and local builds share cache hits. Deliberately outside the product runtimeNo OttaORM, D1, KV, sessions, or RBAC, just token-and-team authorization.
  • @ottabase/cf-pdfHTML-to-PDF on Cloudflare Browser Rendering with static DOM capture, safe download headers, and PDF metadata injection.
  • @ottabase/premium and @ottabase/premium-webhooks (now @ottabase/webhooks)A paid-package framework with offline license verification and entitlements, plus outbound HMAC-signed webhooks as the worked example.
Show 2 more
  • @ottabase/ottaai replaces cf-aiTenant BYOK provider keys encrypted at rest, deterministic resolution, and a Cloudflare AI Gateway transport.
  • One otta CLI for the app lifecyclepnpm otta start <app> --env <name> runs any app or Wrangler environment locally; pnpm otta new web|landing scaffolds a new one.
Minor
1.3.0

Permission + scope authorization

  • Authorization is permission + scope, never role name.Platform authority requires a system-scoped grant carrying platform:admin; org admins hold org:admin scoped to their own tenant.
  • New platform_owner role, separate from the org-scoped owner.Every self-registered user is owner of their own personal organization, so role-name admin gates are gone for good.
  • Admin surface split by capabilityPlatform pages (users, RBAC, infrastructure, appearance, taxonomy) require platform admin, org pages (blog, media, members, settings, audit) require org:admin, and the nav shows only what you hold.
  • Default-deny CRUD on RBAC grant tables and control-plane data, a hardened tenant boundary on member rosters and app-scoped lookups, and Role.ensureDefaultRoles({ heal: true }) to reconcile system roles after an upgrade from /__bootstrap__/seed.
1 breaking change
  • Role names no longer grant anything. hasAdminRole is deleted and gates call assertAdmin with an explicit system or organization scope. Databases seeded under an older definition (a legacy owner = *:*) should run the bootstrap seed step to reconcile.
Minor
1.2.0

Custom auth replaces Auth.js

  • @ottabase/auth 2.0Auth.js swapped for an in-house implementation built entirely on the Web Crypto API. No Auth.js, no Node crypto, no third-party JWT library.
  • Signed HS256 session cookie carries identity claims only.The roles and permissions snapshot lives in a per-session KV registry, so the cookie never approaches the 4KB browser limit.
  • PBKDF2-SHA256 passwords at 100k iterations, CSRF double-submit cookies on every state-changing endpoint, and __Host- prefixed Secure cookies in production.
  • OAuth2 + PKCE with five presets (Google, GitHub, Discord, Microsoft, Auth0), 15-minute magic links, and KV deny-list revocation: sign-out kills one session, a password change kills all of them.
1 breaking change
  • Auth.js and its D1 adapter are gone. Session verification now reads KV on every request, so OBCF_KV must be bound - without it getSession() fails closed and nobody stays signed in.
Minor
1.1.0

Content unification & EmbedApp

  • Unified content modelChangelog, blog, and every content type now share the posts model via a contentType discriminator. No more separate tables.
  • "Blog" renamed to "Content" across the admin UX.Debounced server-side search, content-type tabs, featured/highlighted toggle, and a New dropdown per type.
  • EmbedAppLightweight route group for /embed/* with an iframe-friendly QueryClient. Window-focus refetches disabled, elevated stale/gc times.
  • Docs embed at /embed/docs auto-navigates to the first page and respects the ?theme=dark|light query param.
Major
1.0.0

Open-source launch

  • Public MIT release on github.com/ottabase/ottabase.Ship production-grade multi-tenant SaaS on Cloudflare Workers with the TanStack + Vite template.
  • All 47+ packages bumped to 1.0.0.Dedicated audit worker route extracted and covered by Vitest.
  • CHANGELOG.md added following Keep a Changelog / SemVer.README updated with docs and changelog links.
  • Full stack in one monorepoAuth.js v5, OttaORM, RBAC, RLS, Queues, Cron, Realtime via Durable Objects, Blog/CMS, Brand Engine.
Minor
0.9.0

OttaMenu: 6 renderer types

  • @ottabase/ottamenu ships with sidebar, flyout, mega, navbar, and two more built-in renderer types.
  • OttaORM-backed menu management with nested items, drag reorder, and live preview.
  • Admin CRUD for menus wired into the TanStack app navigation.
Minor
0.8.0

Next.js Homepage template

  • Next.js app spun out as a dedicated homepage template (otta-landing), separate from the TanStack SaaS app.
  • Signal Horizon theme with multi-theme support via CSS custom properties and a theme switcher.
  • Changelog, FAQ, About, Philosophy, Packages, and Docs pages all in place for clone-and-ship marketing sites.
Major
0.7.0

Brand Engine: enhanced

  • @ottabase/brand-engineUnified token-based theming with CSS injection and email branding support.
  • @ottabase/brand-engine-reactBrandProvider, useBrand hook, and automatic layout resolution.
  • @ottabase/ottalayout10 preset layouts with wildcard routing and React slot injection.
  • White-label multi-tenant theming.Per-org design tokens with zero extra config.
Major
0.6.0

RLS, Multi-tenancy, RBAC, Audit, OttaORM++

  • Row-Level Security enforced transparently at query level.Tenants only ever see their own data.
  • RBAC with wildcard permissions (users:*, *:read, *:*) and per-org KV cache with O(1) invalidation.
  • Multi-tenant isolationOrg as tenant boundary with two-level caching (KV + local) for permission lookups.
  • Audit logging with before/after value tracking, request metadata, and compliance-ready change history.
Show 1 more
  • OttaORM fat model upgradesRelationships, lifecycle hooks, field-level validation, and soft deletes.
2 breaking changes
  • Legacy query builder deprecated. Use Drizzle directly or go through OttaORM model methods.
  • Model-level auth is now declarative. Imperative guards in controllers are no longer recommended.
Minor
0.5.0

OttaBlog: blog engine + CMS

  • @ottabase/ottablogPost, Category, Tag, Series, content scheduling, auto-generated RSS and Sitemap.
  • @ottabase/ottaeditor upgraded to 30+ plugins13 EditorJS core plus 17 custom blocks (callout, embed, table-of-contents, and more).
  • @ottabase/ottarendererReact renderer for EditorJS JSON and raw HTML output with syntax highlighting.
Major
0.4.0

Queue system

  • @ottabase/queueLaravel-inspired job queue built on Cloudflare Queues with priority levels, deduplication, and job chaining.
  • Dead letter queue with configurable retry policies and backoff.
  • @ottabase/cronCron handler with static and DB-driven task definitions, full timezone support.
1 breaking change
  • Queue handlers must now use the new dispatch API. Legacy push() wrappers removed.
Patch
0.3.1

Referral system

  • @ottabase/referralsfirst-touch attribution with referral code generation and invite flows.
  • Click tracking and conversion analytics backed by Cloudflare KV.
  • Plugs into Auth.js session creation.No extra middleware required.
Minor
0.3.0

Shortlinks

  • @ottabase/shortlinksURL shortener with expiry dates, optional interstitial pages, and per-link click analytics.
  • OttaORM-backed model with admin CRUD and rate limiting per IP.
Major
0.2.0

TanStack template app

  • Primary production templateTanStack Router v1 + Vite + Cloudflare Workers with file-based routing, auth flows, multi-tenant org setup, and RBAC enforcement out of the box.
  • Unified pnpm dev experienceVite and Wrangler run together from a single command.
  • Bootstrap API for owner account creation.OttaORM auto-migrations on first request.
Minor
0.1.2

OttaORM: fat models and auto CRUD

  • @ottabase/ottaormEloquent-inspired fat models on Cloudflare D1 via Drizzle. Relationships, validation, lifecycle hooks.
  • Model-driven CRUD API auto-generated at /api/ottaorm/{entity} covering GET, POST, PATCH, and DELETE with no boilerplate.
  • Core models shippedUser, Account, Post, Tag. Extend or override freely.
Patch
0.1.1

CF Realtime: Durable Objects pub/sub

  • @ottabase/cf-realtimeWebSocket pub/sub using Cloudflare Durable Objects. No external service needed.
  • Pusher-style API for easy migrationSubscribe to channels, bind events, broadcast from the server.
  • RealtimeBroadcaster publishes from any Worker route; the client reconnects automatically.
Minor
0.1.0

Cloudflare bindings package

  • @ottabase/cftype-safe wrappers for every Cloudflare binding including D1, KV, R2, Images, Queues, Rate Limiting, and Hyperdrive.
  • Consistent Result<T, Error> pattern across all operations.No try/catch scatter.
  • Dev-time bindings via Wrangler miniflare.Zero Cloudflare account required for local development.
Patch
0.0.3

OttaEditor: EditorJS integration

  • @ottabase/ottaeditorEditorJS wrapper with typesafe plugin management and a default plugin bundle.
  • Custom plugin example (AlertPlugin) ships with the template app as a starting point.
Patch
0.0.2

Core packages: db and auth

  • @ottabase/dbGlobal Drizzle D1 driver, shared schema, transactions, and type-safe raw SQL.
  • @ottabase/authAuth.js v5 integration with OAuth and Credentials providers. D1 adapter from day one.
Major
0.0.1

Project genesis

  • Turborepo monorepo with pnpm workspaces.The foundation the discarded Next.js monolith never had.
  • Seed packagesConfig, state, and ui. Each independently versioned from the start.
  • Architecture decisionEvery framework concern lives in packages/ and not inside the app.