OPEN SOURCE2025 →v0.4.2

@mrfinch/booking

Real-time booking for Convex, as a component.

convexopen-sourcecomponent
ROLE
Author & maintainer
RELEASE
v0.4.2 · published on npm
API
Typed queries & mutations
HARDENED FOR
Timezones · DST · midnight

@mrfinch/booking is a Convex component for booking rooms, equipment, people, pooled quantities, and combinations of them. Mount it in your app and call typed functions for resources, schedules, availability and bookings. It owns the inventory; your app owns access control and booking policy.

Why it exists

I first used Cal.com while building Jumper. As the booking flow grew, I wanted its state and availability checks to live in the same database as the rest of the app. A studio session can need a room, equipment and an engineer together; reserving only part of that would leave the band with a booking it cannot use. That became the reason to build my own engine and, later, extract it as a Convex component.

Getting it out of the app took a few attempts. My first monorepo package worked locally and broke on deploy: aliasing Convex's function builders got in the way of its static analysis. Moving to the official component template fixed that.

The booker: event type and duration on the left, a month calendar in the middle, the free slots of the chosen day on the right
The booker: pick a duration, a day, a slot

Install

convex/convex.config.tsts
import { defineApp } from "convex/server";
import booking from "@mrfinch/booking/convex.config";

const app = defineApp();
app.use(booking);
export default app;

What is inside

Exclusive inventory uses a bitmap of 96 fifteen-minute slots per resource and day; pools track quantities. That keeps availability checks bounded by the days a booking spans. Weekly schedules support multiple time windows and date overrides. The host combines them with booking policies such as notice periods and buffers.

Reactive presence shows other visitors which slots someone is considering. The final booking mutation checks and reserves inventory atomically: that is what prevents conflicting bookings. A room plus two microphones plus an engineer either commits together or not at all. Provisional bookings, confirmation, cancellation and rescheduling share the same inventory model.

Transactional email goes through the Resend component mounted inside Booking. Apps can use the built-in templates or provide an optional, typed renderer through an internal Convex query. The app supplies the subject, HTML and plain text; Booking keeps responsibility for delivery. Without a custom renderer, the standard templates still work.

Confirmation screen: a green check, a booked headline, the session details and a Book Another button
Confirmed, with the email on its way and a cancel link inside it
"It has no access to your ctx.auth, no access to process.env, and no opinion about users."From the docs, on what the component knows about your app

Where it runs

The engine grew out of Jumper. Its published npm package now powers the intro-call booking on this portfolio: a dedicated Convex backend, Berlin working hours with a break between two daily windows, private cancel and reschedule links, and guest notifications. On convexbooking.dev, anyone can try the public sandbox against data that resets every hour.

Version 0.4.2 adds the optional app email renderer. This site uses it for its own dark, textured email design. Changing that design now takes a portfolio deployment, without changing or republishing the component. The package also has regression tests for timezones, daylight-saving transitions, midnight boundaries and competing inventory reservations.

The ConvexBooking admin dashboard: counters for event types, bookings, upcoming and pending, a recent bookings list and shortcuts to event types, schedules and the booker
The admin on convexbooking.dev: event types, bookings, schedules, resources

What is still missing

Two-way calendar sync is still missing, so an owner's external appointments do not yet block availability. The component handles individual bookings; recurring leases remain app-level logic in Jumper. It was submitted to the Convex component directory on 22 September 2026. Payments and identity stay in the host app on purpose.

Mr. Finch© 2026 Daniel FinkeStuttgart, DE