Skip to content

PocketBase

Firstly, PocketBase is amazing! It paved the way for single-executable application bases, is incredibly easy-to-use, and a polished experience. Gani, the person behind it, is a mad scientist 🙏.

From a distance, PocketBase and TrailBase are both single-executables providing similar feature sets: REST APIs, realtime updates, authentication, file storage, a runtime for custom endpoints, admin dashboard…, all on top of SQLite1.

To see the differences both on a technical and philosophical level, we’ll have to dive a little deeper…

TrailBase was born out of admiration for PocketBase trying to move the needle in a few areas:

  • Be even lighter and faster. SQLite is astonishingly fast, to the point where even small overheads matter. PocketBase is written in Go, which in itself is a fast language, however FFI overhead matters. This is where a language like Rust with native C ABI support can help.
  • Less abstraction and embracing standards (SQL2, a full ES6 runtime through WASM, JWT, UUID) to avoid lock-in as much as possible, thus simplifying adoption either fully or as piece-meal as well as as moving on if necessary.
  • Untethered access to SQLite3 including features such as recursive CTEs, virtual tables and extensions, e.g., providing vector search and geoip out of the box4, unlocking more use-cases and standard solutions to well-known problems.
  • Be just as easy to self-host with aspirations to be even easier to manage a fleet of deployments across integration tests, development, and production. We’d also like to eventually tackle replication.
  • Be simple, flexible and portable enough to support data analysis use-cases. Imagine a self-contained data science project that ships an interactive UI with vector search and custom JS extensions alongside its data.

Beyond goals and intentions, let’s look at some of the more practical differences:

PocketBase being written in Go and TrailBase in Rust may be the most instantly visible difference. Preference aside, this will likely matter more to folks who want to use either as a framework rather than the standalone binary or modifying the core.

In practice, both languages are solid, speedy options with rich ecosystems. Though Rust’s lack of a runtime and lower FFI overhead gives it the edge in terms of performance. Measuring we found that TrailBase’s APIs are roughly 10x faster. This may sound like a lot but is the result of SQLite itself being extremely fast meaning that even small overheads weigh heavily.

Independently, TrailBase offers a WebAssembly runtime in contrast to PocketBase’s gotcha goja JavaScript interpreter 🙃. The former can support a wide-range of guest languages - currently JS/TS and Rust with more to come - and can allow for a wider range of isolation/performance trade-offs. In practice, a custom Rust WASM endpoint can be up to 140x faster than a PocketBase JS one.

Both PocketBase and TrailBase allow customization using their built-in runtimes. However, some users may want even more control and built their own binaries using only bits and pieces. This is what we refer to as library or framework use. For this use-case language preference and prior experience of you and your team will likely matter a lot more with PocketBase written in Go and TrailBase in Rust.

Framework use is something PocketBase has allowed for a long time and is really great at. TrailBase technically allows it too, but at this point it really feels more like an afterthought while we focus on the standalone experience. Expect TrailBase to improve significantly in this area.

Looking more closely at the breadth of similar features, various differences emerge. In lieu of trying to enumerating all of these constantly evolving differences, let’s look a some of the nifty tricks that TrailBase has up its sleeve:

  • Support for multiple independent SQLite DBs5.
  • Language independent bindings via JSON-schema with strict type-safety enforced all the way from the client to the database6.
  • A WASM runtime for custom endpoints in multiple languages and speed-ups of up to 140x7.
  • Untethered access to SQLite with all its features and capabilities2.
  • First-party client libraries beyond JS/TS and Dart for C#, Kotlin, Swift, Go, Python and Rust.
  • Has a ready, public auth UI (login, profile, …) to get you started. You can fork, modify or roll your own since it’s just a WASM component.
  • Support for geospatial data and GeoJSON APIs.
  • Support for stable more and more efficient cursor-based pagination in addition to OFFSET.
  • Component-provided admin UI extension dashboards.
  • Arguably a less polished admin UI but it works on small mobile screens 😅.

Both PocketBase and TrailBase are truly open-source: they accept contributions and are distributed under OSI-approved licenses. PocketBase is distributed under the permissive MIT license, while TrailBase uses the OSL-3.0 copyleft license. We chose this license over more popular, similar copyleft licenses such as AGPLv3 due to its narrower definition of derivative work that only covers modifications to TrailBase itself. This is similar to GPL’s classpath or LGPL’s linkage exception allowing the use of TrailBase as a framework and JS runtime without inflicting licensing requirements on your original work.

PocketBase is great and both PocketBase and TrailBase are constantly evolving making it hard to give clear guidance on which to pick when. If you can afford the luxury, I’d recommend to give them both a quick spin. After all they’re both incredibly quick and easy to deploy.

In the end, if you’re looking for mileage or framework use-cases you’re likely better off with PocketBase. Otherwise it may be worth giving TrailBase a closer look, especially when flexibility and performance matter.


  1. TrailBase recently gained support for Postgres. It’s still early days and change subscriptions are not supported but it offers a path for folks who feel that they may need finer-grained locking in the future.

  2. We believe that SQL a ubiquitous evergreen technology, which in of itself is already a high-level abstraction for efficient, unified cross-database access. ORMs, on the other hand, often look great in examples but many fall apart for more complex tasks. They’re certainly bespoke, non-transferable knowledge, and lead to vendor lock-in. UPDATE: PocketBase in v0.39 gained an SQL console but special care is needed especially for schema manipulations, since PB manges its own metadata besides the primary schema, which will get out-of-sync. 2

  3. Maybe more in line with SupaBase’s philosophy. We suspect that PocketBase relies on schema metadata by construction requiring alterations to be mediated through PocketBase to keep everything in sync.

  4. All extensions can be built into a small, standalone shared library and imported by vanilla SQLite to avoid vendor lock-in.

  5. This can aid with physical separation and offer a path to overcoming potential locking bottlenecks.

  6. Note that SQLite is not strictly typed by default. Instead column types merely a type affinity for value conversions.

  7. Depends a lot on the guest language and the specific taks in question. 140x is what we measured in heavy computational tasks comparing Goja with Rust->WASM. It’s apples to oranges, yet practically applicable.