How Twenty Is Built
Repository structure, Nx build system, dependencies, testing, and deployment
How Twenty Is Built
This page covers the practical engineering behind Twenty: how the monorepo is organized, what tools orchestrate the build, what dependencies power the features, and how the product gets deployed.
For Product Managers
This page answers "how does the engineering team ship Twenty?" — the tools, processes, and infrastructure behind the product. Understanding this helps you estimate customization effort, deployment complexity, and maintenance costs for self-hosting.
Repository Structure
Twenty is an Nx monorepo with 15+ packages managed by Yarn workspaces. All applications and libraries live in a single repository.
twenty/
├── packages/
│ ├── twenty-server/ ← NestJS backend (API, GraphQL, workers)
│ ├── twenty-front/ ← React SPA (Vite, the main CRM UI)
│ ├── twenty-ui/ ← Shared UI component library
│ ├── twenty-shared/ ← Shared types, utils, constants
│ ├── twenty-emails/ ← Email templates (React Email)
│ ├── twenty-sdk/ ← SDK for app development
│ ├── twenty-website/ ← Marketing site (Next.js)
│ ├── twenty-docs/ ← Documentation (Mintlify)
│ ├── twenty-docker/ ← Docker Compose, K8s, Helm configs
│ ├── twenty-e2e-testing/ ← Playwright E2E tests
│ ├── twenty-zapier/ ← Zapier integration
│ ├── twenty-apps/ ← Plugin/app ecosystem
│ │ ├── internal/ ← First-party apps (self-hosting, call recording)
│ │ └── community/ ← Community apps (Stripe sync, Mailchimp, etc.)
│ ├── twenty-companion/ ← Desktop companion app
│ ├── twenty-cli/ ← CLI tool (deprecated → twenty-sdk)
│ ├── twenty-utils/ ← Dev utilities and release scripts
│ ├── twenty-oxlint-rules/ ← Custom linting rules
│ └── create-twenty-app/ ← App scaffolding CLI
├── nx.json ← Nx monorepo configuration
├── package.json ← Root workspace definition
├── tsconfig.base.json ← Shared TypeScript config
└── .github/workflows/ ← CI/CD (20+ GitHub Actions workflows)The Core Applications
| Package | Technology | Purpose |
|---|---|---|
| twenty-server | NestJS 11 + TypeORM | Backend API, GraphQL, REST, background workers |
| twenty-front | React 18 + Vite 7 | Main CRM single-page application |
| twenty-website | Next.js 14 | Marketing site (twenty.com) |
| twenty-docs | Mintlify | Developer documentation (docs.twenty.com) |
The Shared Libraries
| Package | Purpose |
|---|---|
| twenty-ui | 100+ React components (buttons, tables, kanban, navigation, rich text editor) |
| twenty-shared | TypeScript types, workflow schemas, metadata utils, i18n constants |
| twenty-emails | React Email templates for transactional emails |
| twenty-sdk | SDK for building Twenty apps/plugins + CLI |
Why an Nx Monorepo?
Twenty has 15+ interconnected packages that share types, components, and utilities. Nx ensures: (1) only affected packages are rebuilt when code changes, (2) builds are cached locally and in CI, (3) dependency relationships are tracked automatically. Without Nx, a change to twenty-shared would require manually rebuilding everything — Nx does it automatically.
Build System
Nx as Orchestrator
yarn install ← installs all dependencies (Yarn workspaces)
│
▼
nx build twenty-shared ← build shared libs first (Nx dependency graph)
nx build twenty-ui ← then UI components
│
├──► nx build twenty-front ← Vite production build
└──► nx build twenty-server ← NestJS compilation (TypeScript → JS)Nx features used:
- Task graph — knows build order from package dependencies
- Caching — skips unchanged packages
- Affected —
nx affected:buildonly rebuilds what changed - Parallel — builds independent packages simultaneously
Frontend Build (Vite)
twenty-front → Vite 7
├── SWC (fast TypeScript transpilation)
├── Linaria (CSS extraction at build time)
├── GraphQL Codegen (type generation)
└── Output: static HTML/JS/CSS bundleBackend Build (NestJS)
twenty-server → TypeScript compiler
├── NestJS modules compiled
├── TypeORM entities and migrations
├── GraphQL schema generation (runtime)
└── Output: Node.js application (dist/)Dependency Map
Backend Dependencies (Key Libraries)
| Package | Purpose | Why Chosen |
|---|---|---|
| NestJS 11 | Application framework | Dependency injection, modular architecture, enterprise-grade |
| TypeORM 0.3 | Database ORM | Mature, decorator-based, migration support |
| GraphQL Yoga | GraphQL server | Lightweight, spec-compliant, subscription support |
| @nestjs/graphql | NestJS GraphQL integration | Schema-first with code generation |
| BullMQ | Job queue | Reliable, Redis-backed, supports delays and cron |
| ioredis | Redis client | High-performance, cluster support |
| Passport | Authentication | Modular strategies (JWT, OAuth, SAML) |
| class-validator | Input validation | Decorator-based validation for DTOs |
| googleapis | Google API client | Gmail and Calendar sync |
| @microsoft/microsoft-graph-client | Microsoft Graph | Outlook and Calendar sync |
| stripe | Billing | Payment processing for hosted version |
| ai + @ai-sdk/* | AI integration | Multi-provider AI (OpenAI, Anthropic, Google) |
| imapflow + nodemailer | IMAP sync and SMTP sending |
Frontend Dependencies (Key Libraries)
| Package | Purpose | Why Chosen |
|---|---|---|
| React 18 | UI framework | Industry standard, large ecosystem |
| Vite 7 | Build tool | Fast dev server, optimized production builds |
| Apollo Client | GraphQL client | Mature caching, real-time subscriptions |
| Jotai | State management | Atomic — minimal boilerplate, fine-grained updates |
| Linaria (@wyw-in-js) | CSS-in-JS | Zero-runtime — CSS extracted at build time |
| React Router 6 | Routing | Nested layouts, lazy loading |
| React Hook Form | Forms | Performant, minimal re-renders |
| @blocknote/mantine | Rich text editor | Block-based editor (like Notion) |
| @nivo/* | Charts | Data visualization for analytics |
| @xyflow/react | Flow diagrams | Workflow visual editor |
| Lingui | i18n | Compile-time message extraction |
| Mantine | UI primitives | Accessible component foundation |
| Framer Motion | Animations | Declarative animations |
Infrastructure Dependencies
| Service | Purpose |
|---|---|
| PostgreSQL 16 | Primary database (multi-tenant with schema isolation) |
| Redis | Cache + BullMQ broker + SSE pub/sub |
| ClickHouse | Analytics and usage data |
| S3 (or local storage) | File attachments and uploads |
Key Design Choice: Zero-Runtime CSS
Twenty uses Linaria (via @wyw-in-js), which extracts CSS at build time. Unlike runtime CSS-in-JS libraries (styled-components, Emotion), Linaria adds zero JavaScript overhead — the styles are plain CSS files. This matters for a CRM where users have large tables with hundreds of rows; runtime CSS-in-JS would add measurable overhead per row.
Deployment
Docker Compose (Primary Method)
The simplest deployment uses 4 Docker services:
docker-compose.yml
├── server → Twenty app (NestJS + bundled React frontend)
│ Port 3000
├── worker → BullMQ background workers
│ (same image, different entrypoint)
├── db → PostgreSQL 16
│ Port 5432
└── redis → Redis
Port 6379Quick install:
bash <(curl -sL https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-docker/scripts/install.sh)Manual:
curl -O https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-docker/.env.example
curl -O https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-docker/docker-compose.yml
# Edit .env with your settings
docker compose up -dRequired Environment Variables
| Variable | Purpose |
|---|---|
APP_SECRET | Encryption key (generate with openssl rand -base64 32) |
SERVER_URL | Public URL of the application |
PG_DATABASE_PASSWORD | PostgreSQL password |
STORAGE_TYPE | local or s3 |
Optional Configuration
| Category | Variables |
|---|---|
| Auth | AUTH_GOOGLE_*, AUTH_MICROSOFT_*, SAML/OIDC settings |
EMAIL_DRIVER, SMTP settings | |
| Messaging | Gmail/Microsoft API credentials for email sync |
| Storage | S3 bucket, region, credentials |
| Monitoring | SENTRY_DSN, OpenTelemetry config |
| Analytics | ClickHouse connection |
| AI | OPENAI_API_KEY or other AI provider keys |
Other Deployment Options
| Platform | Type | Maintained By |
|---|---|---|
| Docker Compose | Self-hosted | Core team |
| Kubernetes | Self-hosted (Terraform/Manifests) | Community |
| Railway | Cloud platform | Community template |
| Coolify | Self-hosted PaaS | Community |
| EasyPanel | Self-hosted PaaS | Community |
| Elest.io | Managed hosting | Partner |
| Sealos | Cloud platform | Community |
Quality & Testing
Testing Stack
| Layer | Tool | Scope |
|---|---|---|
| Backend unit/integration | Jest | NestJS modules, services, resolvers |
| Frontend components | Vitest + Storybook 10 | Component rendering and interaction |
| Visual regression | Chromatic | UI screenshot comparison |
| E2E | Playwright | Full user flows (auth, records, workflows) |
| SDK | Vitest | SDK unit + integration tests |
Code Quality Tools
| Tool | Purpose |
|---|---|
| Oxlint | Fast Rust-based linting (custom rules in twenty-oxlint-rules) |
| Prettier | Code formatting |
| TypeScript strict mode | Type safety across all packages |
| GraphQL Codegen | Auto-generated types from GraphQL schemas |
| tsgo | Fast TypeScript type checking (Go-based) |
CI/CD Pipeline
Twenty has 20+ GitHub Actions workflows covering:
- Server, frontend, shared, SDK, docs, website, Zapier — each tested independently
- Docker Compose deployment test
- Breaking changes detection
- Release creation and deployment
- i18n synchronization (Crowdin)
- Preview environments for PRs
- Automated deployment to production on merge to
main
Developer Experience
Getting Started
# Clone the repo
git clone https://github.com/twentyhq/twenty.git && cd twenty
# Use correct Node version
nvm use
# Install dependencies
yarn install
# Start infrastructure (PostgreSQL + Redis)
cd packages/twenty-docker && docker compose -f docker-compose.dev.yml up -d && cd ../..
# Set up environment
cp packages/twenty-server/.env.example packages/twenty-server/.env
# Run database migrations
npx nx database:migrate twenty-server
# Seed the database
npx nx database:seed twenty-server
# Start the app (frontend + backend + worker)
yarn startKey Developer Commands
| Task | Command |
|---|---|
| Start everything | yarn start |
| Start frontend only | npx nx start twenty-front |
| Start server only | npx nx start twenty-server |
| Run server tests | npx nx test twenty-server |
| Run frontend Storybook | npx nx storybook:dev twenty-front |
| Run E2E tests | npx nx test twenty-e2e-testing |
| Generate GraphQL types | npx nx graphql:codegen twenty-front |
| Database migration | npx nx database:migrate twenty-server |
| Lint all | npx nx run-many -t lint |
| Build all | npx nx run-many -t build |
App / Plugin Development
Twenty has an app ecosystem for extensions:
# Scaffold a new Twenty app
npx create-twenty-app my-app
# Build with the SDK
import { TwentySDK } from 'twenty-sdk';Community apps include: Stripe sync, Mailchimp sync, meeting transcripts, LinkedIn browser extension, AI meeting summaries, and more.