Booking.go
A multi-tenant SaaS for slot-based booking, built so a single backend can serve many independent businesses without their data ever crossing.
Overview
Small businesses that run on appointments (a salon, a physiotherapy clinic, a personal trainer, a freelance consultant) all face the same scheduling problem: publish when you are available, let clients book a slot, and keep two people from claiming the same one. Most reach for a calendar and a phone, which works until it doesn't.
Booking.go is a platform that solves this once, for many businesses at the same time. It is multi-tenant: each business owns its services, working hours, holidays, and bookable slots, and one deployment serves all of them while keeping each tenant's data cleanly separated. The data model and access paths are designed around that boundary rather than bolting it on later.
It is two services. The backend (booking-go-engine) is a Node.js and TypeScript API on Express, with a layered architecture that keeps routing, business logic, and data access in separate places. The frontend (booking-go-web) is a Next.js and React app that talks to it. Both are open source and still being built, so the surface is changing as the model settles.
At a glance
- Type
- Multi-tenant SaaS, slot-based booking
- Backend
- booking-go-engine (Express + TypeScript)
- Frontend
- booking-go-web (Next.js 15 + React 19)
- Databases
- PostgreSQL · MongoDB · Redis
- Auth
- JWT access + refresh tokens
- Validation
- Zod (shared across both services)
- Infra
- Docker Compose
- Status
- In active development
How it works
Authenticate the tenant
A business owner registers and signs in. Auth issues short-lived access tokens and longer-lived refresh tokens (JWT), and every request is scoped to the tenant it belongs to.
Describe the business
Each business defines its services, working hours, and holidays. This is the configuration that everything else is generated from, so it is modeled as first-class data rather than free text.
Generate and query slots
From a business's hours and services, the engine generates the slots clients can actually book. Availability queries are read-heavy and repetitive, so results are cached in Redis instead of recomputed on every request.
Run the booking lifecycle
A booking moves through clear states: booked, confirmed, cancelled, completed. The rules that guard those transitions (no double-booking a slot, no booking outside hours) live in the service layer, not scattered across routes.
Capabilities
01Multi-tenant by design
One backend serves many businesses, with each tenant's services, hours, and bookings kept separate. Tenancy is part of the data model and the access paths from the start, which is far cheaper than retrofitting isolation onto a single-tenant app later.
02Layered backend with honest boundaries
The engine follows a strict path: route to service to repository to database. Routing handles HTTP, services hold the business rules, repositories own data access. Each layer has one job, so the rules that matter stay in one place and are easy to test.
03The right store for each job
PostgreSQL holds the relational core (businesses, services, slots, bookings) where consistency matters. MongoDB takes the append-heavy activity logs and notifications. Redis caches sessions and slot availability. Each datastore does what it is good at instead of forcing everything into one.
04Typed end to end
TypeScript spans both services, and inputs are validated with Zod at the edges, so a malformed request is rejected before it reaches the business logic. The frontend is a Next.js and React app using React Query for server state and NextAuth for sessions.
Want the code?
Booking.go is open source and built in public.