I Shipped...

13 May 2026 (7PRs)

markdown serving for AI agents from the Jazz docs

AI coding assistants work better with plain text than with HTML. I added a proxy to the Jazz docs site that serves any page as clean markdown when a request includes an Accept: text/markdown header or a .md suffix in the URL, making it easy for AI agents to read the docs directly.

an RSS feed for the Jazz docs blog

The Jazz docs blog didn't have an RSS feed, so there was no easy way for people to subscribe and be notified of new posts. I added an RSS 2.0 feed at /rss.xml built from all blog posts sorted newest-first, and registered it in the site layout so browsers and feed readers can auto-discover it.

a TypeScript type fix for the SvelteKit plugin in strict mode

Adding the Jazz SvelteKit plugin to vite.config.ts with TypeScript strict mode enabled would fail to compile because the plugin's ssr.external option was typed as string[], but Vite's actual type is true | string[]. I widened the type to match what Vite expects, so it compiles cleanly under strict mode.

a rebuilt world-tour example with a custom globe and Vue tests

The world-tour example app used a third-party map library to display a globe, which was a heavy external dependency. I replaced it with a hand-rolled canvas-based dot globe made from 50,000 Fibonacci sphere points, dropped the dependency entirely, added the example to the monorepo workspace, and included Jazz+Vue integration tests alongside it.

a fix for the browser benchmark suite being hidden from CI

Two separate regressions had quietly broken the browser benchmark tests so they weren't running in CI at all. A recent refactor changed how database insert results are structured, breaking the seed step, and a separate issue prevented the test files from being discovered. I fixed both problems so the benchmark suite runs correctly again.

a fix for deep query subscriptions losing reactivity

When you subscribed to Jazz data with deeply nested relationships — like posts that include authors that include teams — changes more than one level deep wouldn't trigger a UI update. The subscription system only registered top-level tables as dependencies and missed the deeper ones. I fixed the graph compilation step to walk all nesting levels and register every nested table, so deep mutations correctly invalidate subscriptions.

a cleanup of the example apps' docs, tests, and feature parity

Several Jazz example apps had accumulated inconsistencies: some still used Playwright for testing while others had moved to Vitest browser mode, and their docs and feature sets had drifted out of sync. I migrated the remaining auth examples to Vitest browser mode and fixed the various inconsistencies to bring the examples back to parity.

7 May 2026 (3PRs)

dropping an unnecessary fetch polyfill from the Jazz Expo integration

The Expo (React Native) integration for Jazz included a custom fetch polyfill that swapped out the built-in network library for one from expo/fetch. It was originally added to support reading response bodies as streams, but Jazz never actually does that — all fetch calls just grab the whole response at once with .json() or .text(), and real-time sync runs over WebSockets anyway. I removed the polyfill entirely, simplifying the code and preventing potential conflicts with third-party libraries that also try to override the global fetch.

an interactive lens diagram to the migrations documentation

Jazz uses "lenses" to handle schema migrations — they define how old data gets transformed when you change your data model. I added an animated, interactive diagram to the documentation that visualises how data moves through the lens chain, making the concept much easier to grasp than text alone.

a fix for broken polyfills in the Expo integration that were crashing third-party libraries

The Jazz Expo integration included three polyfills (bits of code that patch in missing browser features) for standard web networking types — but these were actually harmful. If they ran before React Native had set up its own network globals, they'd overwrite those globals with undefined, breaking third-party libraries like Clerk. I removed the three useless polyfills while keeping the two that do real work.

6 May 2026 (1PR)

a fix for a React Native UI freeze caused by synchronous database queries

The jazz-rn library was running database queries by blocking the JavaScript thread, which froze the UI during any database access and could also cause deadlocks when the server needed to respond before a query could complete. I converted the query function to be async, so it runs off the JavaScript thread and returns a Promise, keeping the app responsive while waiting for data.

5 May 2026 (1PR)

auto-reloading of Next.js apps when the schema is pushed

During Jazz development, whenever you pushed a new schema, you had to manually refresh the browser to pick up the changes. I added a mechanism where the Jazz Webpack/Turbopack plugin writes a small "schema hash" file to a cache directory on every schema push, and the React provider imports this file during development — so the bundler notices the change and automatically reloads the page for you.

4 May 2026 (1PR)

a fix for a stale repository reference in the create-jazz scaffolding tool

The create-jazz tool, which scaffolds new Jazz projects, had a hardcoded reference to the old repo name garden-co/jazz2. After the repo was renamed back to garden-co/jazz, I updated that one-line constant so the scaffolding tool points to the right place.

1 May 2026 (1PR)

a testing infrastructure cleanup for the chat-react example app

The chat-react example app had two separate test setups running in parallel — one using Playwright and one using vitest browser mode. I consolidated them by moving the Playwright end-to-end test into the main vitest browser test suite and deleting the now-redundant Playwright config. I also cleaned up some leftover React act() wrapper calls that were printing noisy warnings without actually doing anything useful.

30 April 2026 (2PRs)

async example fixes and browser storage eviction guidance in the docs

The docs for setting up a Jazz client had Vue and Svelte code examples missing await before createJazzClient, which returns a Promise — so copying the example would store a pending Promise instead of the actual client. I fixed those snippets and added a new section explaining how browsers can silently delete locally-stored data (called "storage eviction") and how to call navigator.storage.persist() to ask the browser to keep your data safe.

a fix for sign-up failing on React Native after a local-first session

Jazz lets users start as anonymous "local-first" users and later upgrade to a full account. On React Native, this upgrade was broken with the error "Sign up requires an active Jazz session" because the identity proof method was trying to use a WebAssembly module — which React Native doesn't support. I overrode the method in the React Native implementation to use the native mintLocalFirstToken function from jazz-rn instead, making the upgrade flow work on iOS and Android.

29 April 2026 (4PRs)

improved spinner UX and dotenv support for the jazz-tools CLI

The create-jazz setup tool got two improvements. The spinner now advances to "Provisioning Jazz Cloud app" before making the network request, so it no longer looks frozen on the previous step. I also added support for loading .env files so CLI commands like deploy can pick up secrets like JAZZ_ADMIN_SECRET from a .env file instead of requiring them to be set as shell environment variables.

automatic browser reloads when schema changes are pushed in development

When developing with Jazz in watch mode, editing schema.ts now automatically reloads the browser to pick up your changes. Previously you had to manually refresh the page after pushing a schema update to see it take effect. I added a callback that fires after a successful schema push and tells the Vite or SvelteKit dev server to send a full-reload signal to the browser.

a fix for the Expo fetch polyfill rejecting URL and Request objects

On Expo (React Native), Jazz uses a custom fetch wrapper that bridges web-style network calls to the native layer. The web fetch standard allows passing a URL or Request object as input, but the native bridge only accepts plain strings — so libraries like better-auth that use this pattern were crashing. I fixed it by normalising those inputs to a plain string URL plus options before passing them to the native bridge.

a fix for rows vanishing after schema migrations

When you change your database schema (a "migration"), existing data should stay visible under the new schema. There was a bug where rows that existed before a migration would silently disappear — the resolved table name wasn't being carried through to the query engine, causing a "table not found" error that just dropped the rows silently. I fixed this by making sure the resolved table name is passed all the way through the schema-aware query path.