Frequently Asked Questions
Start by creating a new RedwoodJS application using the command yarn create redwood-app ./your-project-name
. Then navigate to the project directory. Install the necessary Twilio helper library in the API workspace with yarn workspace api add twilio
.
Twilio's Programmable Messaging API is used to send SMS reminders. Its Message Scheduling feature enables reliable delivery without building a custom scheduling system. This simplifies development and ensures robust functionality.
Scheduling is handled by the Twilio Node.js helper library and RedwoodJS services. The scheduleReminder
function calculates the appropriate sendAt
time, considering the appointment time and a predefined offset. It uses the user's time zone for display but schedules based on UTC for consistency.
Store appointment times in UTC in your database. The user's time zone is stored separately and is used only for displaying the appointment time in the user's local time and formatting the reminder message. Twilio scheduling always uses UTC.
You need Node.js v18 or later, Yarn, a Twilio account, a Twilio phone number with SMS capability, and a configured Twilio Messaging Service. Familiarity with JavaScript, Node.js, React, GraphQL, and database concepts is helpful.
Twilio's Message Scheduling requires a Messaging Service. It offers benefits like sender ID pools, scalability, and advanced opt-out handling, making it more suitable than sending messages from a single number directly.
While RedwoodJS defaults to SQLite for simplicity, PostgreSQL is recommended for production environments due to its robustness and scalability. You can configure the database connection string in the .env
file.
Your Twilio Account SID, Auth Token, and Messaging Service SID should be stored as environment variables in a .env
file in your project's root directory. RedwoodJS automatically loads these variables, making them available to your services.
The scheduledMessageSid
field in the database stores the unique identifier of the scheduled message returned by Twilio. This allows you to cancel or modify the scheduled reminder later if needed.
The provided code includes functionality to cancel existing reminders using the stored scheduledMessageSid
. This cancellation logic is implemented within the updateAppointment
and deleteAppointment
mutations.
Use the E.164 format (e.g., +15551234567) for phone numbers. This ensures international compatibility. The provided code includes validation to enforce this format.
RedwoodJS uses GraphQL for its API. The appointments.sdl.ts
file defines the schema for appointment data, and appointments.ts
contains resolver functions for interacting with the database and Twilio.
RedwoodJS uses Prisma as its database toolkit. You define the data model in the schema.prisma
file and manage migrations using the Redwood CLI.
You can find your Account SID and Auth Token on the main dashboard ("Account Info") of the Twilio Console after logging in.
The example code schedules the reminder 60 minutes before the appointment. The scheduleReminder
function handles scheduling logic, ensuring the reminder is scheduled within Twilio's constraints (15 minutes to 7 days in the future).
Yes, the SMS reminder content can be customized. The scheduleReminder
function demonstrates formatting the message body and incorporating details like the recipient's name and the appointment time and timezone.
Build Appointment Reminders with RedwoodJS and Twilio SMS
Learn how to build an automated SMS appointment reminder system using RedwoodJS and Twilio that reduces no-shows and improves customer engagement. This comprehensive tutorial shows you how to send SMS reminders via Twilio's Programmable Messaging API and Message Scheduling feature—eliminating the need for custom scheduling infrastructure or cron jobs.
By the end of this RedwoodJS SMS tutorial, you'll have a production-ready application that can:
This guide assumes you understand JavaScript, Node.js, React, GraphQL, and database concepts.
Why Use RedwoodJS and Twilio for SMS Appointment Reminders?
Goal: Build a full-stack appointment reminder application where you manage appointments through a modern GraphQL API, and your system automatically schedules and sends SMS reminders at a configurable time before each appointment.
Problem Solved: Automate appointment reminders to reduce no-shows by up to 38% (industry average). Eliminate manual reminder processes and complex self-hosted scheduling infrastructure by leveraging Twilio's native message scheduling—no background workers or cron jobs required.
Technologies:
System Architecture:
User Browser interacts with Redwood Frontend, which communicates via GraphQL with the Redwood API. The API uses Prisma to talk to the Database and makes calls to the Twilio API.
Prerequisites:
npm install -g yarn
or see yarnpkg.com.Step 1: Set Up Your RedwoodJS Project with Twilio
Let's start by creating a new RedwoodJS application and installing the Twilio SDK for Node.js.
Create the RedwoodJS App: Open your terminal and run the following command, replacing
appointment-reminder-app
with your desired project name:Navigate into the Project Directory:
Install Twilio Helper Library: Install the official Twilio Node.js helper library specifically in the API workspace:
Environment Variables: RedwoodJS uses a
.env
file for environment variables. Create this file in the project root:Add the following variables to your
.env
file. We will obtain these values in Step 4 (Integrating with Twilio). Do not commit this file to version control if it contains sensitive credentials. Redwood's.gitignore
includes.env
by default.TWILIO_ACCOUNT_SID
: Your primary Twilio account identifier.TWILIO_AUTH_TOKEN
: Your secret token for authenticating API requests. Treat this like a password.TWILIO_MESSAGING_SERVICE_SID
: The unique ID for the Twilio Messaging Service you'll configure. Scheduling requires a Messaging Service.DATABASE_URL
: The connection string for your database. Redwood defaults to SQLite for quick setup, but PostgreSQL is recommended for production. Update this connection string according to your database provider (e.g., Railway, Supabase, Heroku Postgres, local installation). For SQLite (default), the line would beDATABASE_URL="file:./dev.db"
.Step 2: Create the Appointment Database Schema with Prisma
Define the database structure for storing appointment data, SMS tracking information, and delivery status using Prisma ORM.
> Note: Prisma 6.16.x Rust-Free Architecture > As of Prisma 6.16.0 (October 2025), the Rust-free version of Prisma ORM is generally available. This architectural change provides: > - Lower CPU footprint by eliminating the extra CPU usage from running the query engine as a binary > - Less deployment complexity, as the query engine binary no longer needs to be compiled for specific operating systems > - Improved performance, especially when working with large datasets >
Define the Prisma Schema: Open
api/db/schema.prisma
and replace its contents with the followingAppointment
model:appointmentTime
: We store the appointment time in UTC. This is crucial for consistent scheduling across time zones.timeZone
: Storing the original time zone allows us to format the time correctly for the user and potentially adjust reminder messages.scheduledMessageSid
: This optional field will hold the unique identifier (Sid
) of the scheduled message returned by Twilio. This is essential if you need to cancel or modify the reminder later.@@index([appointmentTime])
: Added an index to potentially improve query performance when sorting or filtering by appointment time.Apply Migrations: Run the following command to create and apply the database migration. When prompted, give your migration a descriptive name (e.g.,
create_appointment_model
).This command does three things:
Step 3: Build the GraphQL API for SMS Appointment Management
RedwoodJS uses GraphQL for its API layer, providing type-safe queries and mutations. We'll generate the necessary SDL (Schema Definition Language) and service files to handle CRUD operations for appointments and integrate with the Twilio SMS API.
Generate SDL and Service: Use Redwood's generator to scaffold the GraphQL types, queries, mutations, and the service file for the
Appointment
model:This creates:
api/src/graphql/appointments.sdl.ts
: Defines the GraphQL schema (types, queries, mutations).api/src/services/appointments/appointments.ts
: Contains the business logic (resolvers) for the SDL definitions.api/src/services/appointments/appointments.scenarios.ts
: For defining seed data for testing.api/src/services/appointments/appointments.test.ts
: For writing unit tests.Refine the GraphQL Schema: Open
api/src/graphql/appointments.sdl.ts
. Redwood generates basic CRUD operations. We need to adjust the input types slightly, particularly forappointmentTime
.appointmentTime
as aDateTime
(which Apollo Server handles as an ISO 8601 string) and assume it's provided in UTC from the client.@requireAuth
is added for basic authorization (we'll touch on setup later). Remove it if you don't need authentication initially.Implement Service Logic (Including Twilio Integration): This is where the core logic resides. Open
api/src/services/appointments/appointments.ts
and implement the resolvers, including the Twilio scheduling logic within thecreateAppointment
andupdateAppointment
mutations.scheduleReminder
Helper: Encapsulates the logic for calculatingsendAt
, checking Twilio's constraints (15 min - 7 days), canceling previous messages (ifscheduledMessageSid
exists and client is available), formatting the message body with the correct time zone (with fallback), and calling the Twilio API. Now checks for client availability.appointmentTime
(assumed UTC) directly. ThetimeZone
is used only for formatting the message content for the user.+15551234567
) for international compatibility. Validation moved to a helper.try...catch
around Twilio calls and logs errors using Redwood'slogger
. Crucially, it handles potential failures during scheduling and cancellation. Added checks for Twilio client initialization.validateAppointmentInput
helper for consistency increate
andupdate
. Added timezone validation robustness withtry/catch
.updateAppointment
anddeleteAppointment
using the storedscheduledMessageSid
. It logs errors if cancellation fails but generally proceeds with the primary operation (update/delete). Now checks for client availability before attempting cancellation.Step 4: Configure Twilio SMS and Message Scheduling
Now, let's obtain your Twilio API credentials and configure a Messaging Service for SMS appointment reminders. Message Scheduling requires a Messaging Service—you cannot schedule messages using only a phone number.
Get Twilio Account SID and Auth Token:
TWILIO_ACCOUNT_SID
andTWILIO_AUTH_TOKEN
variables in your.env
file.Purchase a Twilio Phone Number:
Create and Configure a Twilio Messaging Service:
Phone Number
. Click Continue.MG
). Copy this value.TWILIO_MESSAGING_SERVICE_SID
variable in your.env
file.Why a Messaging Service? Twilio's Message Scheduling feature requires sending via a Messaging Service. It provides features like sender ID pools, scalability, content intelligence, and advanced opt-out handling, making it superior to sending from a single number directly for applications.
> Important: Twilio Message Scheduling Requirements and Limitations (as of 2025) > > Required: > - Messaging Service SID is mandatory for scheduling. Passing only a
From
phone number will cause scheduling parameters to be dropped and the message to send immediately. > > Scheduling Constraints: > - Minimum advance time: 15 minutes (messages must be scheduled at least 15 minutes in the future) > - Maximum advance time: 35 days (messages cannot be scheduled more than 35 days in advance) > > Capacity Limits: > - Account limit: 1,000,000 scheduled messages at any given time (including subaccounts) > - Subaccount limits are separate from parent account allocation > > Pricing: > - Message scheduling is free; you only pay for messages sent > > Source: Twilio Message Scheduling FAQs and LimitationsRestart Redwood Dev Server: If your development server is running, stop it (
Ctrl+C
) and restart it to load the new environment variables:Step 5: Build the Frontend Interface for Appointment Reminders
Now, let's create the user interface for managing appointments using Redwood's generators and React components.
Generate Pages and Cells: We need pages to list appointments and a form to create/edit them. Redwood Cells handle data fetching gracefully.
Implement
AppointmentsCell
: Openweb/src/components/AppointmentsCell/AppointmentsCell.tsx
. This component fetches and displays the list of appointments.(Implementation details for React components like
AppointmentsCell
,AppointmentForm
,AppointmentsPage
,NewAppointmentPage
,EditAppointmentPage
, andEditAppointmentCell
would follow here, including form handling, date/time input (handling time zones and converting to UTC for the API), displaying appointments, and linking between pages. This typically involves standard React/GraphQL client patterns using Redwood's helpers like<Form>
,<Submit>
,<FieldError>
,useMutation
, etc. A full implementation is beyond the scope of this Markdown rewrite task but would be the next logical step in the tutorial.)