PocketBase v0.9.0stable Released Dec 06, 2022
⚠️ Breaking Change Impact Score: 7/10

PocketBase: v0.9.0 Release

Source available — automated, not human-reviewed

Component: pocketbase · Channel: stable. Automated analysis, not a compatibility certification. How this works.

Analysis updated: 2026-11-01.

Breaking-change evidence from the source

  • This is a minor breaking change if you are using `filesystem.Serve` (eg. as part of a custom `OnFileDownloadRequest` hook):
  • - Changed the `mailer.Mailer` interface (**minor breaking if you are sending custom emails**):
Read the original context ↗
Source flags breaking changes — review applicability
📄 .MD
⚡ Executive Summary (TL;DR)

PocketBase v0.9.0. Source highlight: ⚠️ **As always, make sure to have a copy of your pb_data directory before upgrading.**

Who Does This Impact? (Role-Based Analysis)

💻 Software Engineers & Devs

Check the source notes against the package and APIs you use before upgrading.

📊 Product & Engineering Leads

Use the documented changes to assess relevance to your product; release frequency alone is not a quality measure.

⚙️ DevOps & Security

Verify the target version, runtime requirements and rollback procedure in the official documentation.

⚠️ Breaking Changes & Deprecations (2)

  • This is a minor breaking change if you are using `filesystem.Serve` (eg. as part of a custom `OnFileDownloadRequest` hook):
  • - Changed the `mailer.Mailer` interface (**minor breaking if you are sending custom emails**):

✨ New Features & Capabilities (5)

  • Added the raw OAuth2 user data (`meta.rawUser`) and OAuth2 access token (`meta.accessToken`) to the auth response (#654).
  • Added `Record.OriginalCopy()` method that returns a new `Record` copy populated with the initially loaded record data (useful if you want to compare old and new field values).
  • Added new event hooks:
  • Added support for `Partial/Range` file requests (#1125).
  • Added new `Dao` helpers to make it easier fetching and updating the app settings from a migration:

🔧 Bug Fixes & Patches (2)

  • Fixed concurrent multi-relation cascade update/delete (#1138).
  • Other minor UI fixes and improvements
📄 View Raw Release Notes (Original Developer Log)
> ⚠️ **As always, make sure to have a copy of your pb_data directory before upgrading.** > If you are using PocketBase v0.7.x or older, it is recommended first to upgrade to v0.8. This release mostly contains internal code improvements and the long-awaited automigrate feature. Additionally, we also support writing custom db migrations with JavaScript (_more documentation and examples will be available soon_). This also means that the `migrate` command now works identically with the prebuilt executable and when PocketBase is used as framework (_in the near future there are also plans to allow binding to the app event hooks with JavaScript_). There are no breaking changes to the public apis, but depending which exported internals you use in your app, you may have to update your Go code if you are extending PocketBase. Please refer to the [CHANGELOG](https://github.com/pocketbase/pocketbase/blob/master/CHANGELOG.md#v090) or the notes below for more details. ## Changes - Fixed concurrent multi-relation cascade update/delete ([#1138](https://github.com/pocketbase/pocketbase/issues/1138)). - Added the raw OAuth2 user data (`meta.rawUser`) and OAuth2 access token (`meta.accessToken`) to the auth response ([#654](https://github.com/pocketbase/pocketbase/discussions/654)). - `BaseModel.UnmarkAsNew()` method was renamed to `BaseModel.MarkAsNotNew()`. Additionally, to simplify the insert model queries with custom IDs, it is no longer required to call `MarkAsNew()` for manually initialized models with set ID since now this is the default state. When the model is populated with values from the database (eg. after row `Scan`) it will be marked automatically as "not new". - Added `Record.OriginalCopy()` method that returns a new `Record` copy populated with the initially loaded record data (useful if you want to compare old and new field values). - Added new event hooks: ```go app.OnBeforeBootstrap() app.OnAfterBootstrap() app.OnBeforeApiError() app.OnAfterApiError() app.OnRealtimeDisconnectRequest() app.OnRealtimeBeforeMessageSend() app.OnRealtimeAfterMessageSend() app.OnRecordBeforeRequestPasswordResetRequest() app.OnRecordAfterRequestPasswordResetRequest() app.OnRecordBeforeConfirmPasswordResetRequest() app.OnRecordAfterConfirmPasswordResetRequest() app.OnRecordBeforeRequestVerificationRequest() app.OnRecordAfterRequestVerificationRequest() app.OnRecordBeforeConfirmVerificationRequest() app.OnRecordAfterConfirmVerificationRequest() app.OnRecordBeforeRequestEmailChangeRequest() app.OnRecordAfterRequestEmailChangeRequest() app.OnRecordBeforeConfirmEmailChangeRequest() app.OnRecordAfterConfirmEmailChangeRequest() ``` - The original uploaded file name is now stored as metadata under the `original_filename` key. It could be accessed via: ```go fs, _ := app.NewFilesystem() defer fs.Close() attrs, _ := fs.Attributes(fikeKey) attrs.Metadata["original_name"] ``` - Added support for `Partial/Range` file requests ([#1125](https://github.com/pocketbase/pocketbase/issues/1125)). This is a minor breaking change if you are using `filesystem.Serve` (eg. as part of a custom `OnFileDownloadRequest` hook): ```go // old filesystem.Serve(res, e.ServedPath, e.ServedName) // new filesystem.Serve(res, req, e.ServedPath, e.ServedName) ``` - Refactored the `migrate` command to support **external JavaScript migration files** using an embedded JS interpreter ([goja](https://github.com/dop251/goja)). This allow writting custom migration scripts such as programmatically creating collections, initializing default settings, running data imports, etc., with a JavaScript API very similar to the Go one (_more documentation will be available soon_). The `migrate` command is available by default for the prebult executable, but if you use PocketBase as framework you need register it manually: ```go migrationsDir := "" // default to "pb_migrations" (for js) and "migrations" (for go) // load js files if you want to allow loading external JavaScript migrations jsvm.MustRegisterMigrations(app, &jsvm.MigrationsOptions{ Dir: migrationsDir, }) // register the `migrate` command migratecmd.MustRegister(app, app.RootCmd, &migratecmd.Options{ TemplateLang: migratecmd.TemplateLangJS, // or migratecmd.TemplateLangGo (default) Dir: migrationsDir, Automigrate: true, }) ``` **The refactoring also comes with automigrations support.** If `Automigrate` is enabled (`true` by default for the prebuilt executable; can be disabled with `--automigrate=0`), PocketBase will generate seamlessly in the background JS (or Go) migration file with your collection changes. **The directory with the JS migrations can be committed to your git repo.** All migrations (Go and JS) are automatically executed on server start. Also note that the auto generated migrations are granural (in contrast to the `migrate collections` snapshot command) and allow multiple developers to do changes on the collections independently (even editing the same collection) miniziming the eventual merge conflicts. Here is a sample JS migration file that will be generated if you for example edit a single collection name: ```js // pb_migrations/1669663597_updated_posts_old.js migrate((db) => { // up const dao = new Dao(db) const collection = dao.findCollectionByNameOrId("lngf8rb3dqu86r3") collection.name = "posts_new" return dao.saveCollection(collection) }, (db) => { // down const dao = new Dao(db) const collection = dao.findCollectionByNameOrId("lngf8rb3dqu86r3") collection.name = "posts_old" return dao.saveCollection(collection) }) ``` - Added new `Dao` helpers to make it easier fetching and updating the app settings from a migration: ```go dao.FindSettings([optEncryptionKey]) dao.SaveSettings(newSettings, [optEncryptionKey]) ``` - Moved `core.Settings` to `models/settings.Settings`: ``` core.Settings{} -> settings.Settings{} core.NewSettings() -> settings.New() core.MetaConfig{} -> settings.MetaConfig{} core.LogsConfig{} -> settings.LogsConfig{} core.SmtpConfig{} -> settings.SmtpConfig{} core.S3Config{} -> settings.S3Config{} core.TokenConfig{} -> settings.TokenConfig{} core.AuthProviderConfig{} -> settings.AuthProviderConfig{} ``` - Changed the `mailer.Mailer` interface (**minor breaking if you are sending custom emails**): ```go // Old: app.NewMailClient().Send(from, to, subject, html, attachments?) // New: app.NewMailClient().Send(&mailer.Message{ From: from, To: to, Subject: subject, HTML: html, Attachments: attachments, // new configurable fields Bcc: []string{"[email protected]", "[email protected]"}, Cc: []string{"[email protected]", "[email protected]"}, Headers: map[string]string{"Custom-Header": "test"}, Text: "custom plain text version", }) ``` The new `*mailer.Message` struct is also now a member of the `MailerRecordEvent` and `MailerAdminEvent` events. - Other minor UI fixes and improvements