Best Boilerplates for Booking and Scheduling Apps 2026
Booking Apps: Complexity in the Details
Scheduling software sounds simple until you implement it: recurring availability, time zone handling (DST!), buffer times, calendar sync (Google, Outlook, Apple), webhook notifications, payment collection at booking, and no-show handling. Each feature has edge cases.
Build vs Use Cal.com
Cal.com is the best open source scheduling infrastructure — it's the Stripe of scheduling. For most booking requirements, self-hosting or using Cal.com's hosted version is the right choice.
Build custom only when:
- Booking is deeply integrated with your core product
- Specialized booking logic (multi-resource, dynamic pricing, group sessions)
- White-labeling without Cal.com branding is required
Quick Comparison
| Tool | Price | Calendar Sync | Payments | White-label | Best For |
|---|---|---|---|---|---|
| Cal.com | Free (self-host) / $15/mo | Google, Outlook, Apple | Stripe | ✅ (paid) | Most scheduling needs |
| Calendly | $10-$20/mo | Google, Outlook | Stripe | ❌ | Simple booking |
| Custom Next.js | Dev cost | Google API | Stripe | ✅ | Integrated scheduling |
Cal.com — Best Open Source Booking
Price: Free (MIT) | Creator: Cal.com team
Enterprise-grade scheduling platform. Available types: one-on-one, round-robin (teams), collective, dynamic. Calendar integrations: Google Calendar, Outlook, Apple Calendar, and CalDAV. Payments: Stripe, PayPal. Video: Zoom, Google Meet, Teams. Webhooks for all booking events.
# Self-host Cal.com
git clone https://github.com/calcom/cal.com
cd cal.com
cp .env.example .env
# Configure DATABASE_URL, NEXTAUTH_SECRET, GOOGLE_API_CREDENTIALS, etc.
yarn install && yarn build && yarn db:push
Choose if: You need a complete scheduling product without building from scratch.
Building Custom Booking with Next.js
For scheduling tightly integrated into a SaaS product:
// Time slot availability calculation
function getAvailableSlots(
date: Date,
providerAvailability: Availability[],
existingBookings: Booking[],
duration: number // minutes
): TimeSlot[] {
const dayAvailability = providerAvailability.find(
a => a.dayOfWeek === date.getDay()
);
if (!dayAvailability) return [];
const slots: TimeSlot[] = [];
let current = combineDateTime(date, dayAvailability.startTime);
const end = combineDateTime(date, dayAvailability.endTime);
while (addMinutes(current, duration) <= end) {
const slotEnd = addMinutes(current, duration);
// Check no existing bookings overlap
const isAvailable = !existingBookings.some(booking =>
booking.startTime < slotEnd && booking.endTime > current
);
if (isAvailable) {
slots.push({ startTime: current, endTime: slotEnd, available: true });
}
current = addMinutes(current, duration); // Advance by slot duration
}
return slots;
}
Time Zone Handling
The most common booking app bug: time zones. The rule: store all times in UTC, display in local time.
// Store booking as UTC
const booking = await db.booking.create({
data: {
startTimeUtc: toZonedTime(localTime, providerTimezone).toISOString(),
providerTimezone: 'America/New_York',
attendeeTimezone: attendeeTimezone,
},
});
// Display to attendee in their timezone
const displayTime = format(
toZonedTime(booking.startTimeUtc, booking.attendeeTimezone),
'EEEE, MMMM d, yyyy h:mm a zzz'
);
// "Friday, March 8, 2026 2:00 PM EST"
Google Calendar Integration
import { google } from 'googleapis';
const calendar = google.calendar({ version: 'v3', auth: oauth2Client });
// Create calendar event on booking confirmation
await calendar.events.insert({
calendarId: 'primary',
requestBody: {
summary: `Meeting with ${attendee.name}`,
description: meeting.notes,
start: { dateTime: booking.startTimeUtc, timeZone: 'UTC' },
end: { dateTime: booking.endTimeUtc, timeZone: 'UTC' },
attendees: [{ email: attendee.email }, { email: provider.email }],
conferenceData: {
createRequest: { requestId: booking.id }, // Auto-create Google Meet
},
},
conferenceDataVersion: 1,
});
Compare booking app and SaaS boilerplates on StarterPick.
Check out this boilerplate
View Cal.com on StarterPick →