Deploy Twenty CRM — Self-Hosted, Server + Worker Wired Right [Updated Sep'26]
Self-host Twenty CRM — Salesforce alternative, no per-seat fees
Twenty
Just deployed
/app/packages/twenty/data
Just deployed
/var/lib/postgresql/data
Twenty Worker
Just deployed
Redis
Just deployed
/data
Bucket
Bucket
Just deployed
Deploy and Host Twenty on Railway
Twenty is a modern open-source CRM — a self-hosted Salesforce alternative for managing companies, contacts, opportunities, and custom objects, with a clean Notion-like interface, Kanban pipelines, and a full REST and GraphQL API. This template deploys it the way Twenty is built to run: the server and background worker wired together over Redis with a shared secret, the public URL set to avoid the login-loop trap, and Postgres and file storage configured — so you get a working CRM, not a half-deployed one that can't log in or run workflows.
What This Template Deploys
| Service | Purpose |
|---|---|
| Twenty Server | The API, React frontend, schema, and migrations (port 3000) |
| Twenty Worker | Background jobs — email sync, workflows, and cron (BullMQ) |
| PostgreSQL | Companies, contacts, opportunities, and custom objects |
| Redis | The job queue and cache the worker runs on |
All connect over Railway's private network. The server and worker run the same image as two processes, backed by PostgreSQL for CRM data and Redis for the job queue, with file storage for avatars and attachments — a complete, working CRM stack.
About Hosting
Twenty is a two-process application, and getting that architecture right is the difference between a CRM that works and one that half-loads — this template handles it.
Server and worker are one image doing two jobs — with one shared secret. Twenty runs the same image as a server (the API, React frontend, and migrations) and a separate worker (email sync, workflow runs, and cron via BullMQ). The worker isn't optional: without it, background jobs, email, and automations silently never run. Both must share an identical APP_SECRET/ENCRYPTION_KEY — it encrypts secrets at rest and signs sessions, so a mismatch breaks logins and data. This template generates one secret and wires it to both.
SERVER_URL must match your domain — or login loops forever. This is the most common Twenty failure: if SERVER_URL (and the frontend base URL) don't exactly match the HTTPS domain you access Twenty on, the login page redirects in an infinite loop. This template sets it to your Railway public domain, so authentication works on the first try instead of trapping you at the sign-in screen.
Redis is required — the worker won't run without it. Twenty's background queue runs on Redis (BullMQ), so a missing REDIS_URL makes the worker exit immediately and email sync, workflows, and scheduled jobs never fire. This template wires Redis over the private network, so the queue works out of the box.
File storage — local volume or S3. Avatars and attachments need somewhere to live: this template configures storage (a persistent volume with STORAGE_TYPE=local, or S3-compatible object storage via STORAGE_TYPE=s3 and the STORAGE_S3_* variables — MinIO or a Railway Bucket work without extra config). Either way, uploads survive redeploys. There's no env-var admin: open your Railway domain and Twenty presents a Get Started wizard to create the workspace admin; members join by invite. Logs are set to error,warn, since Twenty's default verbosity floods a platform's log rate limit on a quiet instance.
Typical cost: ~$10–20/month on Railway for the four services — server and worker use ~0.5 GB RAM each at idle, so a small team fits a modest plan; scale up past 10 active users. Twenty is AGPL-3.0 and free, with no user, record, or feature caps — versus Twenty's own cloud at $9+/user/month and Salesforce's per-seat pricing.
How It Compares
| Twenty (self-hosted) | Salesforce | HubSpot | Twenty Cloud | |
|---|---|---|---|---|
| Cost model | Flat infra | Per seat (high) | Freemium + per seat | Per user/month |
| Custom objects | Yes | Yes | Limited | Yes |
| API | REST + GraphQL | Yes | Yes | REST + GraphQL |
| Modern UX | Yes (Notion-like) | Dated | Yes | Yes |
| Data ownership | Full — your infra | Vendor | Vendor | Vendor |
| Self-hostable | Yes | No | No | No |
Salesforce and HubSpot are powerful but expensive per seat and keep your customer data on their servers. Twenty's own cloud is convenient but still per-user. Twenty self-hosted's edge is a modern, developer-friendly CRM — custom objects, Kanban pipelines, and REST/GraphQL APIs — at flat infrastructure cost with no per-seat fees, on infrastructure you own.
Deploy in Under 5 Minutes
- Click Deploy on Railway — the server, worker, PostgreSQL, and Redis build and wire together (~4 minutes)
- Confirm
APP_SECRETis shared by server and worker, andSERVER_URLmatches your Railway domain - Wait for the server to run migrations and the worker to connect to Redis
- Open your Railway domain and complete the Get Started wizard to create your admin
- Add companies, contacts, and a pipeline, or import contacts via CSV or the API
Invite teammates from settings — the first account is the workspace admin.
Common Use Cases
- Sales pipeline of record — companies, people, and opportunities in Kanban stages, replacing a spreadsheet or seat-metered CRM
- Product-to-CRM sync — push signups, trials, and usage into custom objects over the REST or GraphQL API
- Internal ops database — track vendors, applicants, or assets as custom objects with views and an API
- Salesforce/HubSpot replacement — a modern CRM without per-seat licensing
Configuration
| Variable | Required | Description |
|---|---|---|
APP_SECRET | Generated | Encrypts secrets and signs sessions — identical on server and worker |
SERVER_URL | Required | Your Railway HTTPS domain — must match, or login loops |
PG_DATABASE_URL | Auto-injected | PostgreSQL connection for CRM data |
REDIS_URL | Auto-injected | Redis for the BullMQ job queue — the worker needs it |
STORAGE_TYPE / STORAGE_S3_* | Configurable | local on a volume, or s3 for object storage |
One shared secret, and match the URL.
APP_SECRETmust be identical on server and worker (it signs sessions and encrypts data), andSERVER_URLmust equal your Railway domain or login redirects infinitely. This template wires both correctly.
Redis and the worker are required. The worker runs email sync, workflows, and cron over Redis (BullMQ) — without them those never fire. Both are wired here, and file storage is set for avatars and attachments.
Dependencies for Twenty Hosting
- Railway account — ~$10–20/month for the four services, scaling with team size
- PostgreSQL and Redis (both included and wired via Railway references)
- File storage — a volume (local) or an S3-compatible bucket for uploads
- A modern browser to run the CRM; CSV or the API to import contacts
Deployment Dependencies
Implementation Details
The template deploys Twenty as two processes from the same pinned twentycrm/twenty image: twenty-server (the NestJS API, React frontend, schema setup, and migrations on port 3000) and twenty-worker (background jobs — email sync, calendar, workflow triggers, and cron — via BullMQ over Redis), both wired to a shared PostgreSQL and Redis over Railway's private network. Both processes require an identical APP_SECRET/ENCRYPTION_KEY, which encrypts secrets at rest and signs sessions; the template generates one and applies it to both, since a mismatch breaks authentication and stored data.
SERVER_URL must match the public HTTPS domain exactly, or the frontend login redirects in an infinite loop — the most common self-hosted Twenty failure — so it is set to the Railway domain. Redis is mandatory for the worker (a missing REDIS_URL causes it to exit), and file storage for avatars and attachments is configured either on a volume (STORAGE_TYPE=local) or via S3-compatible object storage (STORAGE_TYPE=s3 with STORAGE_S3_*), where MinIO or a Railway Bucket work without extra configuration because Twenty's S3 driver uses path-style addressing.
On first load the public domain presents a Get Started wizard that creates the sole workspace admin; members join by invite. Log verbosity is set to error,warn, as Twenty's default output exceeds the platform's log rate limit on a quiet instance. A /healthz check guards the public service, and PostgreSQL and file storage are the backup targets.
Frequently Asked Questions
Why does Twenty's login loop forever? Almost always SERVER_URL — it must exactly match the HTTPS domain you access Twenty on, or the frontend redirects endlessly at sign-in. This template sets it to your Railway domain, so login works on the first try.
Why does the worker need Redis? Twenty's background queue runs on Redis (BullMQ), so a missing REDIS_URL makes the worker exit and email, workflows, and scheduled jobs never fire. Redis is included and wired here.
Can I import my existing contacts? Yes — Twenty supports CSV import for contacts and companies, and its REST and GraphQL APIs let you sync data programmatically from other systems.
Why Deploy Twenty 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 Twenty on Railway you get a modern open-source CRM with the hard parts solved — server and worker wired over Redis with a shared secret, the public URL set so login works, and Postgres and file storage configured. Manage companies, contacts, and pipelines with no per-seat fees, self-hosted on infrastructure you own.
Template Content