@mrfinch/booking
Real-time booking for Convex, as a component.
- ROLE
- Author & maintainer
- RELEASE
- v0.4.2 · published on npm
- DIRECTORY
- Listed on convex.dev · Sep 2026
- HARDENED FOR
- Timezones · DST · midnight
@mrfinch/booking is a Convex component for booking rooms, equipment, people, pooled quantities and combinations of them. You mount it in your app and call typed functions for resources, schedules, availability and bookings. On 24 September 2026 the Convex team approved it for the official Convex Components Directory.
Why it exists
The first version of Jumper ran its bookings through Cal.com. That worked, more or less. But Cal.com is built around people and their appointments, and its API is designed that way. Rooms and other resources are not really what it is for.
My first idea was a kind of Cal.com component that keeps the state of the Cal.com API in sync with Convex. Thinking it through, I would have lost exactly what I wanted from Convex. Bookings would not run in a transaction, so nothing would reliably stop a double booking, and availability would not update live. On X and YouTube people call themselves Convex-pilled. Once you have experienced the developer experience of Convex, it is hard to do without it. So I decided to build the booking backend directly in Convex.

The first week
I started on 20 November 2025, working with Claude Code. Most of that week was concept work: what is the first slice I can actually ship, and what does a hello world for a booking engine look like. Eight days later the engine had its own repository, based on the official Convex component template, and version 0.1.0 was on npm.
The core idea was mine. Instead of querying wide date ranges of existing bookings, I wanted to slice each day into fixed pieces and store which of them are taken. Claude gave me the right terms and the context for it. That is what I enjoy most about working this way. I can have an idea for how something could work better, even if I could never program it from scratch, and then try it, test it and think through the trade-offs of each approach together with the agent. I learn a lot that way.
Install
import { defineApp } from "convex/server";
import booking from "@mrfinch/booking/convex.config";
const app = defineApp();
app.use(booking);
export default app;What is inside
Each resource gets one document per day with 96 fifteen-minute slots, and a booking records the slots it occupies. An availability check reads only the days a booking spans, however many bookings already exist. Pools track quantities. Weekly schedules support several time windows per day and date overrides.
The booking mutation checks and reserves everything in one transaction. A room with two microphones and an engineer either commits together or not at all. Other visitors see live which slots someone is considering, and the transaction decides who gets them. Provisional bookings, confirmation, cancellation and rescheduling all use the same inventory.
Email goes through the Resend component mounted inside Booking. Apps can use the built-in templates or render their own through an internal Convex query. Delivery stays in the component.

Where the line is
From the start I meant it to be a "dumb" component that handles booking and nothing else. Wherever business logic matters, it belongs in the app, because it depends on the use case. Booking primitives stay in the component. Sign-in, permissions, payments and rules about who may book what live in the host app. Recurring bookings are an example: in Jumper they are app logic built on top of single bookings, so they never went into the package.
Where it runs
In January 2026 I started the second version of Jumper on top of the component. In April I pulled the component into Jumper as a local copy. I kept running into bugs, or things I wanted, while working on Jumper, and rebuilding the npm package for every experiment made no sense. So the package on npm stood still for five months.
Version 0.3.0 in September brought the fixes back, from a copy that had been running in another production project. Most of them were about timezones, daylight saving time and bookings across midnight. Some bugs simply showed up in use. The models and harnesses had also improved and could reason longer and deeper about the code, so they found new ones. I had test cases written and went through them one by one. The package now has 503 tests.
The component also runs the intro-call booking on this site, with two windows a day, the second one ending at midnight. Setting that up turned up one more bug: an end time of 24:00 did not work. Version 0.4.1 fixed it the same afternoon. On convexbooking.dev anyone can try a public sandbox whose data resets every hour.

What is still missing
Two-way calendar sync. An owner's appointments in an external calendar do not block availability in the component yet.