Twenty CRM
Modern open-source CRM with a beautiful interface, Salesforce alternative.
Overview
Twenty is a modern, open-source Customer Relationship Management (CRM) platform designed as a powerful alternative to Salesforce and other proprietary CRM solutions. Built with a focus on user experience and developer-friendly architecture, Twenty offers a clean, intuitive interface while providing the flexibility to customize objects, fields, and workflows to match specific business needs. The platform emphasizes modern web technologies and GraphQL APIs, making it highly extensible for developers who need to integrate CRM functionality into their existing systems.
This Docker deployment creates a complete Twenty CRM environment using four specialized containers: the main Twenty application server, a dedicated worker container for background job processing, a PostgreSQL database for persistent data storage, and Redis for caching and session management. The worker container runs the same Twenty image but executes background tasks like email processing, data synchronization, and scheduled operations, ensuring the main application remains responsive under heavy loads.
This configuration is ideal for businesses seeking a self-hosted CRM solution with enterprise-grade features but without the complexity of cloud vendor lock-in. Sales teams, marketing departments, and customer success organizations can benefit from Twenty's modern interface and customization capabilities, while IT teams appreciate the containerized deployment that can be easily scaled, backed up, and integrated into existing infrastructure management workflows.
Key Features
- Custom object and field creation with flexible data modeling beyond standard CRM entities
- GraphQL API with full schema introspection for seamless third-party integrations
- Dedicated background worker processing for email campaigns, data imports, and scheduled tasks
- Modern React-based interface with real-time updates and collaborative editing features
- Local file storage system with configurable paths for document and attachment management
- JWT-based authentication with separate token secrets for access, login, refresh, and file operations
- PostgreSQL-powered data integrity with support for complex queries and reporting
- Redis-backed session management and caching for improved application performance
Common Use Cases
- 1Small to medium businesses replacing Salesforce or HubSpot with a self-hosted alternative
- 2Sales teams needing custom pipeline stages and deal tracking with specific business logic
- 3Marketing departments managing lead nurturing campaigns with custom contact properties
- 4Customer success teams tracking account health and renewal opportunities with tailored dashboards
- 5Development teams building integrated business applications that need embedded CRM functionality
- 6Organizations with strict data privacy requirements needing on-premises CRM deployment
- 7Consultancies and agencies managing multiple client relationships with custom project tracking fields
Prerequisites
- Docker and Docker Compose installed with at least 2GB RAM available for the complete stack
- Port 3000 available for the Twenty web interface and API access
- Environment variables configured for database password and JWT token secrets
- Basic understanding of CRM concepts like contacts, companies, deals, and sales pipelines
- Familiarity with PostgreSQL for database maintenance and backup procedures
- Knowledge of Redis caching concepts for performance optimization and troubleshooting
For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms
docker-compose.yml
docker-compose.yml
1services: 2 twenty: 3 image: twentycrm/twenty:latest4 container_name: twenty5 environment: 6 - SERVER_URL=${SERVER_URL}7 - FRONT_BASE_URL=${FRONT_URL}8 - PG_DATABASE_URL=postgres://twenty:${DB_PASSWORD}@db:5432/twenty9 - REDIS_URL=redis://redis:637910 - STORAGE_TYPE=local11 - STORAGE_LOCAL_PATH=/app/docker-data12 - ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}13 - LOGIN_TOKEN_SECRET=${LOGIN_TOKEN_SECRET}14 - REFRESH_TOKEN_SECRET=${REFRESH_TOKEN_SECRET}15 - FILE_TOKEN_SECRET=${FILE_TOKEN_SECRET}16 volumes: 17 - twenty-data:/app/docker-data18 ports: 19 - "3000:3000"20 depends_on: 21 - db22 - redis23 networks: 24 - twenty-network25 restart: unless-stopped2627 worker: 28 image: twentycrm/twenty:latest29 container_name: twenty-worker30 command: ["yarn", "worker:prod"]31 environment: 32 - PG_DATABASE_URL=postgres://twenty:${DB_PASSWORD}@db:5432/twenty33 - REDIS_URL=redis://redis:637934 - STORAGE_TYPE=local35 - STORAGE_LOCAL_PATH=/app/docker-data36 - ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}37 - LOGIN_TOKEN_SECRET=${LOGIN_TOKEN_SECRET}38 - REFRESH_TOKEN_SECRET=${REFRESH_TOKEN_SECRET}39 volumes: 40 - twenty-data:/app/docker-data41 depends_on: 42 - twenty43 networks: 44 - twenty-network45 restart: unless-stopped4647 db: 48 image: postgres:15-alpine49 container_name: twenty-db50 environment: 51 - POSTGRES_USER=twenty52 - POSTGRES_PASSWORD=${DB_PASSWORD}53 - POSTGRES_DB=twenty54 volumes: 55 - postgres-data:/var/lib/postgresql/data56 networks: 57 - twenty-network58 restart: unless-stopped5960 redis: 61 image: redis:7-alpine62 container_name: twenty-redis63 volumes: 64 - redis-data:/data65 networks: 66 - twenty-network67 restart: unless-stopped6869volumes: 70 twenty-data: 71 postgres-data: 72 redis-data: 7374networks: 75 twenty-network: 76 driver: bridge.env Template
.env
1# Twenty CRM2SERVER_URL=http://localhost:30003FRONT_URL=http://localhost:30004DB_PASSWORD=secure_twenty_password56# Generate each with: openssl rand -base64 327ACCESS_TOKEN_SECRET=your_access_token_secret8LOGIN_TOKEN_SECRET=your_login_token_secret9REFRESH_TOKEN_SECRET=your_refresh_token_secret10FILE_TOKEN_SECRET=your_file_token_secretUsage Notes
- 1Web UI at http://localhost:3000
- 2Create first workspace
- 3Modern Salesforce alternative
- 4Custom objects and fields
- 5GraphQL API available
Individual Services(4 services)
Copy individual services to mix and match with your existing compose files.
twenty
twenty:
image: twentycrm/twenty:latest
container_name: twenty
environment:
- SERVER_URL=${SERVER_URL}
- FRONT_BASE_URL=${FRONT_URL}
- PG_DATABASE_URL=postgres://twenty:${DB_PASSWORD}@db:5432/twenty
- REDIS_URL=redis://redis:6379
- STORAGE_TYPE=local
- STORAGE_LOCAL_PATH=/app/docker-data
- ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}
- LOGIN_TOKEN_SECRET=${LOGIN_TOKEN_SECRET}
- REFRESH_TOKEN_SECRET=${REFRESH_TOKEN_SECRET}
- FILE_TOKEN_SECRET=${FILE_TOKEN_SECRET}
volumes:
- twenty-data:/app/docker-data
ports:
- "3000:3000"
depends_on:
- db
- redis
networks:
- twenty-network
restart: unless-stopped
worker
worker:
image: twentycrm/twenty:latest
container_name: twenty-worker
command:
- yarn
- worker:prod
environment:
- PG_DATABASE_URL=postgres://twenty:${DB_PASSWORD}@db:5432/twenty
- REDIS_URL=redis://redis:6379
- STORAGE_TYPE=local
- STORAGE_LOCAL_PATH=/app/docker-data
- ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}
- LOGIN_TOKEN_SECRET=${LOGIN_TOKEN_SECRET}
- REFRESH_TOKEN_SECRET=${REFRESH_TOKEN_SECRET}
volumes:
- twenty-data:/app/docker-data
depends_on:
- twenty
networks:
- twenty-network
restart: unless-stopped
db
db:
image: postgres:15-alpine
container_name: twenty-db
environment:
- POSTGRES_USER=twenty
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=twenty
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- twenty-network
restart: unless-stopped
redis
redis:
image: redis:7-alpine
container_name: twenty-redis
volumes:
- redis-data:/data
networks:
- twenty-network
restart: unless-stopped
Quick Start
terminal
1# 1. Create the compose file2cat > docker-compose.yml << 'EOF'3services:4 twenty:5 image: twentycrm/twenty:latest6 container_name: twenty7 environment:8 - SERVER_URL=${SERVER_URL}9 - FRONT_BASE_URL=${FRONT_URL}10 - PG_DATABASE_URL=postgres://twenty:${DB_PASSWORD}@db:5432/twenty11 - REDIS_URL=redis://redis:637912 - STORAGE_TYPE=local13 - STORAGE_LOCAL_PATH=/app/docker-data14 - ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}15 - LOGIN_TOKEN_SECRET=${LOGIN_TOKEN_SECRET}16 - REFRESH_TOKEN_SECRET=${REFRESH_TOKEN_SECRET}17 - FILE_TOKEN_SECRET=${FILE_TOKEN_SECRET}18 volumes:19 - twenty-data:/app/docker-data20 ports:21 - "3000:3000"22 depends_on:23 - db24 - redis25 networks:26 - twenty-network27 restart: unless-stopped2829 worker:30 image: twentycrm/twenty:latest31 container_name: twenty-worker32 command: ["yarn", "worker:prod"]33 environment:34 - PG_DATABASE_URL=postgres://twenty:${DB_PASSWORD}@db:5432/twenty35 - REDIS_URL=redis://redis:637936 - STORAGE_TYPE=local37 - STORAGE_LOCAL_PATH=/app/docker-data38 - ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}39 - LOGIN_TOKEN_SECRET=${LOGIN_TOKEN_SECRET}40 - REFRESH_TOKEN_SECRET=${REFRESH_TOKEN_SECRET}41 volumes:42 - twenty-data:/app/docker-data43 depends_on:44 - twenty45 networks:46 - twenty-network47 restart: unless-stopped4849 db:50 image: postgres:15-alpine51 container_name: twenty-db52 environment:53 - POSTGRES_USER=twenty54 - POSTGRES_PASSWORD=${DB_PASSWORD}55 - POSTGRES_DB=twenty56 volumes:57 - postgres-data:/var/lib/postgresql/data58 networks:59 - twenty-network60 restart: unless-stopped6162 redis:63 image: redis:7-alpine64 container_name: twenty-redis65 volumes:66 - redis-data:/data67 networks:68 - twenty-network69 restart: unless-stopped7071volumes:72 twenty-data:73 postgres-data:74 redis-data:7576networks:77 twenty-network:78 driver: bridge79EOF8081# 2. Create the .env file82cat > .env << 'EOF'83# Twenty CRM84SERVER_URL=http://localhost:300085FRONT_URL=http://localhost:300086DB_PASSWORD=secure_twenty_password8788# Generate each with: openssl rand -base64 3289ACCESS_TOKEN_SECRET=your_access_token_secret90LOGIN_TOKEN_SECRET=your_login_token_secret91REFRESH_TOKEN_SECRET=your_refresh_token_secret92FILE_TOKEN_SECRET=your_file_token_secret93EOF9495# 3. Start the services96docker compose up -d9798# 4. View logs99docker compose logs -fOne-Liner
Run this command to download and set up the recipe in one step:
terminal
1curl -fsSL https://docker.recipes/api/recipes/twenty-crm/run | bashTroubleshooting
- Twenty container failing to start with database connection errors: Verify DB_PASSWORD environment variable matches between twenty and db services, and ensure PostgreSQL container is fully initialized before Twenty starts
- GraphQL API returning 500 errors on queries: Check that all four JWT token secrets (ACCESS_TOKEN_SECRET, LOGIN_TOKEN_SECRET, REFRESH_TOKEN_SECRET, FILE_TOKEN_SECRET) are set and consistent between twenty and worker containers
- Background jobs not processing in worker container: Ensure Redis container is running and accessible, verify REDIS_URL environment variable format is redis://redis:6379 in worker service
- File uploads failing with storage errors: Check that twenty-data volume is properly mounted and STORAGE_LOCAL_PATH=/app/docker-data is correctly configured in both twenty and worker services
- Performance issues with large datasets: Monitor PostgreSQL memory usage and consider increasing shared_buffers, verify Redis memory limits are appropriate for your session and cache requirements
- Twenty web interface not loading after container restart: Ensure SERVER_URL and FRONT_BASE_URL environment variables match your actual domain/IP configuration and are accessible from client browsers
Community Notes
Loading...
Loading notes...
Download Recipe Kit
Get all files in a ready-to-deploy package
Includes docker-compose.yml, .env template, README, and license
Components
twentytwenty-workerpostgresqlredis
Tags
#crm#sales#twenty#salesforce-alternative#business
Category
Productivity & CollaborationAd Space
Shortcuts: C CopyF FavoriteD Download