Learn from OSS
Twenty

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

PackageTechnologyPurpose
twenty-serverNestJS 11 + TypeORMBackend API, GraphQL, REST, background workers
twenty-frontReact 18 + Vite 7Main CRM single-page application
twenty-websiteNext.js 14Marketing site (twenty.com)
twenty-docsMintlifyDeveloper documentation (docs.twenty.com)

The Shared Libraries

PackagePurpose
twenty-ui100+ React components (buttons, tables, kanban, navigation, rich text editor)
twenty-sharedTypeScript types, workflow schemas, metadata utils, i18n constants
twenty-emailsReact Email templates for transactional emails
twenty-sdkSDK 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
  • Affectednx affected:build only 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 bundle

Backend 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)

PackagePurposeWhy Chosen
NestJS 11Application frameworkDependency injection, modular architecture, enterprise-grade
TypeORM 0.3Database ORMMature, decorator-based, migration support
GraphQL YogaGraphQL serverLightweight, spec-compliant, subscription support
@nestjs/graphqlNestJS GraphQL integrationSchema-first with code generation
BullMQJob queueReliable, Redis-backed, supports delays and cron
ioredisRedis clientHigh-performance, cluster support
PassportAuthenticationModular strategies (JWT, OAuth, SAML)
class-validatorInput validationDecorator-based validation for DTOs
googleapisGoogle API clientGmail and Calendar sync
@microsoft/microsoft-graph-clientMicrosoft GraphOutlook and Calendar sync
stripeBillingPayment processing for hosted version
ai + @ai-sdk/*AI integrationMulti-provider AI (OpenAI, Anthropic, Google)
imapflow + nodemailerEmailIMAP sync and SMTP sending

Frontend Dependencies (Key Libraries)

PackagePurposeWhy Chosen
React 18UI frameworkIndustry standard, large ecosystem
Vite 7Build toolFast dev server, optimized production builds
Apollo ClientGraphQL clientMature caching, real-time subscriptions
JotaiState managementAtomic — minimal boilerplate, fine-grained updates
Linaria (@wyw-in-js)CSS-in-JSZero-runtime — CSS extracted at build time
React Router 6RoutingNested layouts, lazy loading
React Hook FormFormsPerformant, minimal re-renders
@blocknote/mantineRich text editorBlock-based editor (like Notion)
@nivo/*ChartsData visualization for analytics
@xyflow/reactFlow diagramsWorkflow visual editor
Linguii18nCompile-time message extraction
MantineUI primitivesAccessible component foundation
Framer MotionAnimationsDeclarative animations

Infrastructure Dependencies

ServicePurpose
PostgreSQL 16Primary database (multi-tenant with schema isolation)
RedisCache + BullMQ broker + SSE pub/sub
ClickHouseAnalytics 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 6379

Quick 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 -d

Required Environment Variables

VariablePurpose
APP_SECRETEncryption key (generate with openssl rand -base64 32)
SERVER_URLPublic URL of the application
PG_DATABASE_PASSWORDPostgreSQL password
STORAGE_TYPElocal or s3

Optional Configuration

CategoryVariables
AuthAUTH_GOOGLE_*, AUTH_MICROSOFT_*, SAML/OIDC settings
EmailEMAIL_DRIVER, SMTP settings
MessagingGmail/Microsoft API credentials for email sync
StorageS3 bucket, region, credentials
MonitoringSENTRY_DSN, OpenTelemetry config
AnalyticsClickHouse connection
AIOPENAI_API_KEY or other AI provider keys

Other Deployment Options

PlatformTypeMaintained By
Docker ComposeSelf-hostedCore team
KubernetesSelf-hosted (Terraform/Manifests)Community
RailwayCloud platformCommunity template
CoolifySelf-hosted PaaSCommunity
EasyPanelSelf-hosted PaaSCommunity
Elest.ioManaged hostingPartner
SealosCloud platformCommunity

Quality & Testing

Testing Stack

LayerToolScope
Backend unit/integrationJestNestJS modules, services, resolvers
Frontend componentsVitest + Storybook 10Component rendering and interaction
Visual regressionChromaticUI screenshot comparison
E2EPlaywrightFull user flows (auth, records, workflows)
SDKVitestSDK unit + integration tests

Code Quality Tools

ToolPurpose
OxlintFast Rust-based linting (custom rules in twenty-oxlint-rules)
PrettierCode formatting
TypeScript strict modeType safety across all packages
GraphQL CodegenAuto-generated types from GraphQL schemas
tsgoFast 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 start

Key Developer Commands

TaskCommand
Start everythingyarn start
Start frontend onlynpx nx start twenty-front
Start server onlynpx nx start twenty-server
Run server testsnpx nx test twenty-server
Run frontend Storybooknpx nx storybook:dev twenty-front
Run E2E testsnpx nx test twenty-e2e-testing
Generate GraphQL typesnpx nx graphql:codegen twenty-front
Database migrationnpx nx database:migrate twenty-server
Lint allnpx nx run-many -t lint
Build allnpx 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.

What's Next