Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How to Build an Appointment Scheduling System in FlutterFlow

Build an appointment scheduling system using Firestore collections for providers (with working hours and specialties), appointments (with dateTime, duration, and status), and services. Users select a provider, pick a date with FlutterFlow's DateTimePicker, see available time slots calculated from the provider's working hours minus existing bookings, and book by creating an appointment document. Include confirmation notifications and a 24-hour cancellation policy check.

What you'll learn

  • How to model providers, services, and appointments in Firestore
  • How to calculate available time slots from working hours and existing bookings
  • How to build a booking flow with date selection and tappable time chips
  • How to enforce cancellation policies and send confirmation notifications
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner9 min read20-30 minFlutterFlow Free+March 2026RapidDev Engineering Team
TL;DR

Build an appointment scheduling system using Firestore collections for providers (with working hours and specialties), appointments (with dateTime, duration, and status), and services. Users select a provider, pick a date with FlutterFlow's DateTimePicker, see available time slots calculated from the provider's working hours minus existing bookings, and book by creating an appointment document. Include confirmation notifications and a 24-hour cancellation policy check.

Provider-based scheduling with available time slots and booking management

An appointment scheduling system lets users pick a provider, choose an available time slot, and book. This tutorial builds one in FlutterFlow using Firestore for data storage, FlutterFlow's built-in DateTimePicker for date selection (no custom calendar widget needed), and a Custom Function to calculate available slots by subtracting booked times from the provider's working hours. The system includes confirmation, cancellation with a 24-hour policy, and a provider dashboard for managing upcoming appointments.

Prerequisites

  • A FlutterFlow project with Firebase/Firestore connected
  • Firebase Authentication enabled with user sign-in working
  • Basic understanding of Backend Queries, Custom Functions, and Action Flows
  • Cloud Functions enabled for confirmation notifications (optional)

Step-by-step guide

1

Create the Firestore data model for providers, services, and appointments

Create a providers collection with fields: userId (String), displayName (String), avatarUrl (String), specialty (String: 'Doctor', 'Dentist', 'Therapist', etc.), rating (Double), workingHours (Map: {startHour: 9, endHour: 17, daysOfWeek: [1,2,3,4,5]} where 1=Monday, 7=Sunday), and slotDurationMinutes (Integer: 30 or 60). Create a services collection with fields: name (String), durationMinutes (Integer), price (Double), and providerId (String). Create an appointments collection with fields: userId (String), providerId (String), serviceId (String), dateTime (Timestamp), duration (Integer, minutes), status (String: 'confirmed', 'cancelled', 'completed'), notes (String, optional), and createdAt (Timestamp). Set Firestore rules: users can read providers and services, users can read and create their own appointments, and providers can read and update appointments assigned to them.

Expected result: Firestore has providers, services, and appointments collections with working hours metadata and status tracking.

2

Build the provider selection page with ratings and specialties

Create a ProvidersPage with a ListView bound to a Backend Query on the providers collection. Add a ChoiceChips filter for specialty (All, Doctor, Dentist, Therapist, etc.) and a sort DropDown (Rating, Name). Each provider card is a Component showing: CircleImage (avatar), displayName Text, specialty badge Container, rating displayed as stars (Row of 5 Icon widgets, filled or outlined based on rating value via Conditional Styling), and a Text showing available days. Tapping a provider navigates to the BookingPage passing the provider document reference. Add a search TextField for finding providers by name.

Expected result: Users see a filterable list of providers with ratings, specialties, and avatars. Tapping a provider starts the booking flow.

3

Calculate and display available time slots for a selected date

On the BookingPage, display the provider's info at the top. Add a DateTimePicker (date only mode) defaulting to today, with min date set to today and max date set to 30 days ahead. When a date is selected, create a Custom Function named getAvailableSlots that: (1) takes the provider's workingHours (startHour, endHour), slotDurationMinutes, and the selected date; (2) generates all possible slots from startHour to endHour in increments of slotDurationMinutes (e.g., 9:00, 9:30, 10:00, ... 16:30 for a 30-min slot with 9-17 hours); (3) queries existing appointments for this provider on the selected date with status != 'cancelled'; (4) removes booked slots from the list; (5) checks that the selected date's day-of-week is in the provider's daysOfWeek array. Display available slots as a Wrap widget of tappable Chip-style Containers, each showing the time (e.g., '10:30 AM'). Booked slots are greyed out or hidden. Tapping an available slot stores it in Page State selectedSlot.

Expected result: After selecting a date, available time slots appear as tappable chips. Booked and past slots are excluded.

4

Book the appointment and send confirmation

Below the time slots, add a service DropDown (filtered by this providerId) and an optional notes TextField. Add a Book Appointment button that activates only when a date, time slot, and service are selected (Conditional Enabling). On Tap Action Flow: Create Document in appointments with userId (current user), providerId, serviceId, dateTime (combine selected date + selected slot time into a Timestamp), duration (from the service's durationMinutes), status 'confirmed', notes, and createdAt as server timestamp. After creation, show a confirmation BottomSheet displaying the appointment details: provider name, date, time, service, and a calendar-add suggestion. Optionally, call a Cloud Function to send a confirmation email or push notification to both the user and provider. Navigate back to a MyAppointmentsPage.

Expected result: Booking creates an appointment document and shows a confirmation. The slot is now taken and will not appear for other users.

5

Build the My Appointments page with cancellation policy

Create a MyAppointmentsPage with two tabs: Upcoming and Past. Upcoming tab: ListView of appointments where userId equals current user, status equals 'confirmed', and dateTime is in the future, ordered by dateTime ascending. Each row shows: provider name, service name, date and time, and a Cancel button. The Cancel button's On Tap Action Flow: first check if the appointment dateTime is more than 24 hours from now using a Custom Function that compares dateTime - DateTime.now() > 24 hours. If yes, show a confirmation dialog, then update the appointment status to 'cancelled'. If under 24 hours, show a message: 'Appointments cannot be cancelled within 24 hours. Please contact the provider directly.' Past tab: appointments where dateTime is in the past, with a 'Leave Review' option. Providers see their own dashboard with a similar layout filtered by providerId.

Expected result: Users see their upcoming and past appointments. Cancellation is allowed only 24+ hours before the appointment time.

Complete working example

Appointment Scheduling Architecture
1Firestore Data Model:
2 providers/{providerId}
3 userId: String
4 displayName: String ("Dr. Sarah Chen")
5 avatarUrl: String
6 specialty: String ("Dentist")
7 rating: Double (4.8)
8 workingHours: Map
9 startHour: Integer (9)
10 endHour: Integer (17)
11 daysOfWeek: List<Integer> [1, 2, 3, 4, 5]
12 slotDurationMinutes: Integer (30)
13 services/{serviceId}
14 name: String ("Dental Cleaning")
15 durationMinutes: Integer (60)
16 price: Double (150.00)
17 providerId: String
18 appointments/{appointmentId}
19 userId: String (patient)
20 providerId: String
21 serviceId: String
22 dateTime: Timestamp (2026-03-30 10:30)
23 duration: Integer (60 minutes)
24 status: String ("confirmed" | "cancelled" | "completed")
25 notes: String (optional)
26 createdAt: Timestamp
27
28Booking Page:
29 Provider Info Card (avatar, name, specialty, rating)
30 DateTimePicker (date only, min: today, max: +30 days)
31 Wrap (available time slot chips)
32 Container (time chip, e.g., "10:30 AM")
33 Available: tappable, theme primary outline
34 On Tap Set Page State: selectedSlot
35 DropDown (service selection, filtered by provider)
36 TextField (notes, optional)
37 Button ("Book Appointment")
38 On Tap Create appointment doc Confirmation BottomSheet
39
40Available Slots Calculation (Custom Function):
411. Generate all slots: startHour to endHour, step slotDurationMinutes
422. Query existing appointments for provider + date (status != cancelled)
433. Remove booked slot times from generated list
444. If date == today, remove slots in the past
455. Return remaining available slots as List<String>
46
47My Appointments Page:
48 TabBar (Upcoming | Past)
49 Upcoming Tab
50 ListView (appointments, confirmed, future, orderBy dateTime ASC)
51 Row Provider name + Service + Date/Time + Cancel button
52 Cancel: if > 24h away update status "cancelled"
53 Past Tab
54 ListView (appointments, past dates)
55 Row Details + Leave Review button

Common mistakes when building an Appointment Scheduling System in FlutterFlow

Why it's a problem: Showing all 24 hours as available slots instead of filtering by the provider's working hours

How to avoid: Store working hours (startHour, endHour, daysOfWeek) on the provider document. The slot generation Custom Function only creates slots within these bounds. If the selected date's day-of-week is not in daysOfWeek, show 'Provider not available on this day'.

Why it's a problem: Not checking for double-booking when two users select the same slot simultaneously

How to avoid: Use a Firestore transaction in a Cloud Function for the booking: atomically check if an appointment already exists for the provider + dateTime, and only create the new one if the slot is still free. Return an error if the slot was taken.

Why it's a problem: Using a Timestamp comparison for slot matching without accounting for time zones

How to avoid: Convert all times to UTC before storing and querying. Display times in the user's local time zone using a Custom Function. Be consistent: always store UTC, always display local.

Best practices

  • Store provider working hours on the provider document for dynamic slot generation
  • Generate available slots by subtracting booked appointments from the provider's schedule
  • Filter out past time slots when the selected date is today
  • Use a Firestore transaction for booking to prevent double-booking race conditions
  • Enforce cancellation policies with a time threshold check (24 hours) before allowing status changes
  • Send confirmation notifications to both user and provider after booking
  • Add a composite Firestore index on providerId + dateTime for efficient appointment queries

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

Write a Custom Function for FlutterFlow that generates available time slots for a provider given their working hours (start hour, end hour, slot duration) and a list of existing appointments on the selected date. Return only the unbooked slots.

FlutterFlow Prompt

Create a booking page with a provider info card at the top, a date picker, a grid of available time slot chips, a service dropdown, and a Book Appointment button. Available slots should update when the user changes the date.

Frequently asked questions

How is this different from the booking system with calendar integration tutorial?

The calendar integration tutorial uses a table_calendar Custom Widget with color-coded days showing availability. This tutorial uses FlutterFlow's simpler built-in DateTimePicker widget for date selection without a custom calendar, making it easier to implement but with less visual richness.

How do I send appointment reminders?

Create a scheduled Cloud Function that runs daily. Query appointments where dateTime is within the next 24 hours and status is confirmed. For each, create a notification document and optionally send a push notification via Firebase Cloud Messaging.

Can I add recurring appointments?

Yes. Add a recurrence field on the appointment (weekly, biweekly, monthly) and a Cloud Function that creates future appointment documents. When booking a recurring appointment, generate the next N occurrences and check each for conflicts before creating.

How do I handle providers with different slot durations per service?

Store durationMinutes on the service document instead of (or in addition to) the provider. When generating available slots, use the selected service's duration to determine slot length. A 30-minute cleaning and a 90-minute root canal would generate different slot patterns.

How do I allow providers to block off vacation days?

Create a provider_unavailability collection with fields providerId, startDate, endDate, and reason. When generating available slots, query this collection for the selected date. If the date falls within an unavailability range, show 'Provider unavailable' instead of time slots.

Can RapidDev help build a full scheduling platform?

Yes. A production scheduling platform needs Google Calendar sync, SMS reminders, waitlists, payment collection at booking, multi-location support, and no-show tracking. RapidDev can architect the complete system with integrations beyond what the visual builder provides.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.