Deploy Cal.com — Open Source Calendly Alternative
Self-hosted scheduling with Postgres — no per-seat booking fees
Cal.com
Just deployed
Just deployed
/var/lib/postgresql/data
Deploy and Host Cal.com on Railway
Cal.com is the leading open-source scheduling platform — a self-hosted alternative to Calendly and Acuity. Share a booking link, let people pick a slot, and sync it to Google, Outlook, or CalDAV automatically. Unlimited event types, unlimited bookings, no per-seat fees, and your customers' calendar data stays on infrastructure you own. This template deploys Cal.com with a managed PostgreSQL database, pre-wired and persistent.
What This Template Deploys
| Service | Purpose |
|---|---|
| Cal.com | The Next.js scheduling app, booking pages, and admin on port 3000 |
| PostgreSQL | Users, event types, bookings, and encrypted calendar credentials |
Both services run on Railway's private network with credentials injected automatically. Railway handles SSL and domain provisioning, and Prisma runs the database migrations on first boot.
About Hosting Cal.com
Cal.com is a Next.js application, and that creates one specific pitfall on any container platform that catches most self-hosters: NEXT_PUBLIC_WEBAPP_URL is compiled into the app at build time, not read at runtime. Any variable prefixed NEXT_PUBLIC_ is baked into the client bundle when the image is built, so setting it afterward as an environment variable does nothing — booking links, OAuth redirect URIs, and confirmation-email links all point at localhost and break. This template supplies that URL at build time so your links resolve to your real domain from the first boot.
Two secrets must be generated once and then never changed:
NEXTAUTH_SECRETsigns user sessions —openssl rand -base64 32CALENDSO_ENCRYPTION_KEYencrypts every stored calendar credential (Google and Microsoft OAuth tokens). It is 24 bytes, not 32 —openssl rand -base64 24. Change it and every connected calendar is permanently corrupted and must be reconnected by hand.
Cal.com also needs DATABASE_DIRECT_URL alongside DATABASE_URL; Prisma uses the direct connection to run migrations. Both are wired to the Railway Postgres service here.
The database is not just app data — it holds OAuth tokens granting read/write access to your users' real calendars. Treat it as sensitive and back it up regularly.
Typical cost: ~$5–15/month on Railway for a small instance with Postgres. Cal.com's own cloud starts at $12/user/month for team features, so self-hosting removes per-seat billing entirely.
How It Compares
| Cal.com (self-hosted) | Calendly | Acuity | Cal.com Cloud | |
|---|---|---|---|---|
| Cost model | Flat ~$5–15/mo infra | Per user/month | Per user/month | From $12/user/mo |
| Event types | Unlimited | Limited on free | Per plan | Unlimited |
| Data ownership | Full | Vendor | Vendor | Cal-hosted |
| Calendar sync | Google, Outlook, CalDAV | Google, Outlook | Google, Outlook | Same |
| Custom branding | Full | Higher tiers | Higher tiers | Team plans |
| Self-hostable | Yes | No | No | No |
Calendly and Acuity are more polished out of the box. Cal.com wins on unlimited event types at a flat cost, full branding control, and keeping your customers' calendar credentials on your own infrastructure.
Deploy in Under 5 Minutes
- Click Deploy on Railway — Cal.com and PostgreSQL build automatically (the Next.js build takes a few minutes)
- Confirm
NEXT_PUBLIC_WEBAPP_URLis set to your Railway domain as a build argument, andNEXTAUTH_URLmatches it - Confirm
NEXTAUTH_SECRETand the 24-byteCALENDSO_ENCRYPTION_KEYare set — and save both externally - Open your Railway domain; Cal.com redirects to the
/auth/setupwizard - Create your admin account, set your availability, and share your first booking link
Configure the EMAIL_SERVER_* variables so booking confirmations and reminders send.
Common Use Cases
- Calendly replacement — share booking links with unlimited event types and no per-seat fees
- Team scheduling — round-robin and collective event types route bookings across a team
- Client-facing booking pages — branded scheduling for consultants, coaches, and agencies on your own domain
- Support and office hours — recurring availability windows with buffer times and booking limits
- Embedded scheduling — drop Cal.com booking widgets into your own site or app
Configuration
| Variable | Required | Description |
|---|---|---|
NEXT_PUBLIC_WEBAPP_URL | Required (build arg) | Your Railway domain — compiled into the app at build time, not runtime |
NEXTAUTH_URL | Required | Same as your public URL — used for authentication callbacks |
NEXTAUTH_SECRET | Required | Session signing key — openssl rand -base64 32, keep stable |
CALENDSO_ENCRYPTION_KEY | Required | Credential encryption — openssl rand -base64 24 (24 bytes). Never change it |
DATABASE_URL | Auto-injected | PostgreSQL connection string via Railway reference variable |
DATABASE_DIRECT_URL | Auto-injected | Direct connection for Prisma migrations — same as DATABASE_URL |
NEXT_PUBLIC_LICENSE_CONSENT | Pre-set | agree — acknowledges the AGPLv3 self-host terms |
CALCOM_TELEMETRY_DISABLED | Optional | Set 1 to disable telemetry |
EMAIL_FROM | Required | Sender address for booking emails |
EMAIL_SERVER_HOST | Required | SMTP hostname |
EMAIL_SERVER_PORT | Required | SMTP port, e.g. 587 |
EMAIL_SERVER_USER | Required | SMTP username |
EMAIL_SERVER_PASSWORD | Required | SMTP password |
NEXT_PUBLIC_WEBAPP_URLmust be a build argument. It is compiled into the client bundle, so setting it only at runtime leaves booking and OAuth links pointing atlocalhost. This is the single most common broken self-hosted Cal.com deployment.
CALENDSO_ENCRYPTION_KEYis 24 bytes and permanent. It encrypts stored calendar credentials. Changing it corrupts every connected calendar. Generate it once, back it up externally, and never rotate it.
Dependencies for Cal.com Hosting
- Railway account — Hobby plan (~$5–15/month) covers both services
- An SMTP provider for booking confirmations and reminders
- Optional: Google Cloud OAuth credentials for Google Calendar sync
- Optional: Microsoft Azure app credentials for Outlook sync
Deployment Dependencies
- Cal.com GitHub Repository
- Cal.com Docker Repository
- Cal.com Self-Hosting Documentation
- Railway Variables Documentation
Implementation Details
The template runs the official calcom/cal.com image on port 3000 against a managed Railway PostgreSQL service. Because NEXT_PUBLIC_WEBAPP_URL is a Next.js public variable, it is provided as a build argument so the correct domain is compiled into the client bundle rather than defaulting to localhost — the failure that breaks booking links, OAuth redirects, and email URLs on naive deployments.
Both DATABASE_URL and DATABASE_DIRECT_URL point at the Postgres service; Prisma uses the direct URL to apply migrations, which run automatically on startup when schema changes are present. NEXTAUTH_SECRET and the 24-byte CALENDSO_ENCRYPTION_KEY are generated at deploy time and must persist unchanged, since the encryption key protects stored OAuth tokens for connected calendars.
All application data lives in PostgreSQL, including the encrypted calendar credentials. That database is both your bookings and a set of tokens with read/write access to real calendars, so it should be backed up on a schedule and treated as sensitive.
Frequently Asked Questions
My booking links point at localhost — why? NEXT_PUBLIC_WEBAPP_URL was set at runtime instead of build time. It's compiled into the app, so it must be a build argument set to your real domain. This template handles that; if you fork it, preserve the build-arg setup.
Why is CALENDSO_ENCRYPTION_KEY only 24 bytes? Cal.com's credential encryption expects a 24-byte key — generate it with openssl rand -base64 24, not 32. Using the wrong length or changing it later permanently corrupts every stored calendar credential.
Do my calendar connections survive a redeploy? Yes, provided CALENDSO_ENCRYPTION_KEY stays constant. The OAuth tokens are encrypted with it and stored in Postgres; the key must not change or they become unreadable.
Why does it need DATABASE_DIRECT_URL? Prisma uses a direct database connection to run migrations, separate from the pooled connection the app uses. Both are wired to the same Railway Postgres here.
Is the self-hosted version free? Yes. Cal.com's community edition is AGPLv3 with no per-seat fees. Some enterprise features require a license, but core scheduling and calendar sync are fully open.
How do I enable Google Calendar sync? Create a Google Cloud project, enable the Calendar and People APIs, configure the OAuth consent screen, and add credentials with your Railway domain as the redirect URI. Then set the Google client ID and secret in Cal.com.
Do I need SMTP? Yes, for booking confirmations, reminders, and password resets. Configure the EMAIL_SERVER_* variables with your provider before going live.
Why Deploy Cal.com on Railway?
Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.
By deploying Cal.com on Railway you get open-source scheduling with the build-time pitfall already solved — Cal.com and PostgreSQL pre-wired over a private network, the webapp URL compiled correctly, encryption keys generated, automatic HTTPS, and Prisma migrations run for you. Unlimited event types, no per-seat billing, and your customers' calendar credentials on infrastructure you own.
Template Content
