Skip to content

Upgrading

Ten hops, newest first. Start at the one above the version you are on and work downwards — or, if you are coming from 0.12, start at the bottom and work up.

You are on Read What it does to you
0.26 0.26 → 0.27 A cron schedule that restricts both day fields runs on either one, so it runs more often, and a schedule with a malformed number is refused, so that job stops running. A key whose isId strategy its type cannot honour stops the boot. On Rebase Cloud, a deploy or preview fails when a function or cron file does not load.
0.25 0.25 → 0.26 A write naming a multi-hop via relation, a role name that is not one role, a local storage page token from before the upgrade and a functions upstream that cannot work are refused. OAuth sign-in settles an unverified account instead of answering local-account-unverified, the MCP server no longer sends REBASE_TOKEN to the app, and generated types drop the key of an excludeFromApi belongsTo. On Rebase Cloud, rebase cloud webhooks and --scale-to-zero true are retired, and older tokens may need creating again.
0.24 0.24 → 0.25 ?count= on a REST list becomes the switch for the count behind meta.total, so a filter on a column named count goes inside ?where=; the remote MCP’s list_collections sends its listing only in the text block, without structuredContent; and @rebasepro/app no longer exports the Spanish translation table es. A plain OPTIONS to a route with no handler, colliding table names at boot, an upsert on the users collection, page with offset, an empty string on a required field and an administrator’s password that fails the password policy are refused. Sessions last 30 days of inactivity by default, client.cron calls /api/admin/cron, offline reads that cannot be answered in full fail with OFFLINE, and a few internal exports and unused props are gone.
0.23 0.23 → 0.24 The SQL db push and db generate render moves out of drizzle/ into the uncommitted .rebase/sql/, the --generate flag of rebase dev is gone because dev always regenerates the SDK types, and a live schema edit commits no SQL. Permissions become scopes: admin surfaces ask for a scope rather than the admin role, API keys hold scopes instead of a permission list and an admin flag, and schema-admin is no longer an administrator. A relative --collections is read from where the command runs, an upsert into a trashed row and an update that changes a key are refused, the remote MCP endpoint takes the SDK’s arguments, and open realtime sockets, email-verification links, signUp and MFA recovery codes change how they treat a session.
0.21 – 0.22 0.21 → 0.23 An API key on a nested path needs read on its parents, unreadable numeric variables and session lifetimes refuse to boot, a custom auth repository needs unlinkUserIdentity, and guest upgrades take the register captcha. 0.22 declares no breaking change, so this is one hop from 0.21.
0.18 – 0.20 0.18 → 0.21 context.client.data stops compiling in a collection callback — query through context.data — and selectedEntities gives way to a selection that can stand for rows nobody has loaded. 0.19 and 0.20 declare no breaking change, so this is one hop from 0.18.
0.17 0.17 → 0.18 Eleven breaking changes, most of them compile errors rather than silent behaviour changes. rebase.data disappears at runtime, peer ranges narrow to carets, and the Node floor moves to 22.22.0.
0.14 – 0.16 0.14 → 0.17 The admin packages are renamed, resources are declared rather than configured, and a bundle built before it will not boot on a current runtime. 0.15 and 0.16 break nothing, so this is one hop from 0.14.
0.13 0.13 → 0.14 Every wire key is camelCase, and anonymous sign-in is opt-in.
0.12 0.12 → 0.13 The largest hop, and the only one that changes who can read your data. It removes the auth schema, renames packages, changes what id means, drops CJS, moves the admin panel to react-router 8, and fixes three ways access could be granted that you did not ask for.

Each page’s sections are in the order you have to make them, and each one names the symptom you would otherwise debug from the wrong end.

Then, whichever hop you made:

[ ] grep for authenticated() and (auth|rebase).uid() IS NOT NULL in config/collections/
[ ] decide the intent of each rule; rewrite the ones that meant "public"
[ ] replace not(authenticated()) with serverContext()
[ ] if realtime.requireAuth was true with an AuthAdapter, treat the socket as
having been open — verify RLS on every subscribable collection (section 2)
[ ] SELECT ... FROM pg_policies — record the qual of every policy BEFORE
[ ] update package names and imports
[ ] grep for rebase.data — it is now rebase.dataAsAdmin (section 8)
[ ] grep for the other ten removed deprecated exports (section 8)
[ ] drop react-router-dom; import RouterProvider from "react-router/dom"
[ ] check node >= 22.22.0 and react >= 19.2.7 (react-router 8 requires both)
[ ] move defaultSecurityRules into config/collections/index.ts
[ ] grep for .userId
[ ] grep for row.id on tables not keyed on id
[ ] run db push
[ ] run rebase doctor --policies — expect no Insecure or Orphaned entries
[ ] SELECT ... FROM pg_policies again — confirm every intended change landed
[ ] exercise the app signed OUT, in a private window — watch the websocket too
--- 0.13 → 0.14 (part 2) ---
[ ] re-run rebase generate-sdk, then build — the compiler finds row.author_id
[ ] grep for snake_case where/orderBy keys; a stale one is a 400, not a warning
[ ] grep for raw fetch consumers reading row.<something>_id — these read
undefined and raise nothing
[ ] if the project was introspected, re-run rebase schema introspect
[ ] decide anonymous sign-in: set auth.allowAnonymous: true, or confirm you
never used it (grep for signInAnonymously)
[ ] drop @rebasepro/client-postgres from package.json
--- 0.14 → 0.17 (part 3) ---
[ ] rename @rebasepro/admin → @rebasepro/cms and admin-types → cms-types,
and RebaseAdmin → RebaseCMS
[ ] move dataSources / storageSources out of the backend config into
rebase.json and config/, then `rebase build` — an old bundle will not boot
[ ] grep collections for admin.titleProperty; it is refused at boot now
[ ] grep crons for ctx.client and for `userId` as an identity key
[ ] rename --legacy to --workspace wherever build/start is scripted
[ ] if you implement EmailService yourself, `send` must return a result

rebase doctor --policies is the one to wire into CI: it exits non-zero on a policy still carrying the permissive tautology, and on one an earlier push superseded. The pg_policies reads before and after are still worth the minute — they show you the expressions themselves, which is the only way to spot a fail-open policy written in a spelling the detector does not match. Neither the packages nor the type system will tell you: the change lives in the database, and db push is the only thing that puts it there.

  • Changelog — the release notes each of these sections summarises
  • Compatibility — the six contracts, and which ones a version can break
  • CLI Commands — rebase doctor and the commands the checklists run