Twenty CRM Architectural Explanations: A Deep Dive into the Monorepo Structure and Feature Design

Twenty CRM provides comprehensive architectural explanations in its open-source repository, documenting a modular NestJS backend, React frontend with Jotai state management, and Nx monorepo organization that powers features like Workflows, Contacts, and Messaging.

Twenty CRM is an open-source customer relationship management platform built with modern architectural patterns that prioritize maintainability and extensibility. The project maintains detailed architectural explanations within its CLAUDE.md file and throughout the source code, describing how the monorepo structure separates concerns between frontend, backend, and shared utilities. Understanding these Twenty CRM architectural explanations helps developers extend core features such as Workflow automation, Messaging, and dynamic metadata management.

Monorepo Architecture Overview

Twenty CRM organizes its codebase as an Nx monorepo workspace that cleanly separates applications and libraries into distinct packages. This structure enables shared configuration, consistent linting, and fast builds across the entire stack.

The package layout follows this structure:


packages/
├── twenty-front/          # React frontend application

├── twenty-server/         # NestJS backend API

├── twenty-ui/             # Shared UI components library

├── twenty-shared/         # Common types and utilities

├── twenty-emails/         # Email templates with React Email

├── twenty-website/        # Next.js documentation website

├── twenty-zapier/         # Zapier integration

└── twenty-e2e-testing/    # Playwright E2E tests

Source: CLAUDE.md – Package Structure

Technology Stack

According to the Twenty CRM architecture documentation, the tech stack includes:

  • Frontend – React 18, TypeScript, Jotai, Linaria, Vite
  • Backend – NestJS, TypeORM, PostgreSQL, Redis, GraphQL-Yoga
  • Monorepo – Nx + Yarn 4

Source: CLAUDE.md – Tech Stack

Backend Architecture: NestJS Modular Design

The backend follows NestJS modular design principles, with each domain (Contacts, Messaging, Workflow) encapsulated in its own module under packages/twenty-server/src/modules/. Modules encapsulate providers, services, and controllers, then compose into higher-level modules via imports.

Dynamic Metadata System

Twenty CRM supports customizable object schemas through the metadata modules located at packages/twenty-server/src/engine/metadata-modules/. This engine handles dynamic object definitions, view configurations, and schema migrations, allowing users to create custom objects without database changes.

Workflow Feature Architecture

The Workflow feature demonstrates this modularity clearly. Located at packages/twenty-server/src/modules/workflow/, the implementation separates concerns across sub-modules:


src/modules/workflow/
│   workflow.module.ts          ← top-level module
│   workflow-trigger/
│   workflow-status/
│   workflow-builder/
│   workflow-executor/
│   workflow-runner/

The top-level workflow.module.ts only wires the essential sub-modules:

// packages/twenty-server/src/modules/workflow/workflow.module.ts
import { Module } from '@nestjs/common';
import { WorkflowStatusModule } from 'src/modules/workflow/workflow-status/workflow-status.module';
import { WorkflowTriggerModule } from 'src/modules/workflow/workflow-trigger/workflow-trigger.module';

@Module({
  imports: [WorkflowTriggerModule, WorkflowStatusModule],
})
export class WorkflowModule {}

Source: workflow.module.ts

Workflow Execution Flow

The architecture separates three distinct responsibilities:

  1. Trigger – WorkflowTriggerWorkspaceService validates versions and creates workflow runs
  2. Runner – WorkflowRunnerWorkspaceService executes runs through the executor
  3. Status – WorkflowStatusModule manages state transitions and event emission

Key implementations reside in:

This separation ensures triggers decide when to start, runners decide how to execute, and status modules decide what to record.

Frontend Architecture: State and Styling

The Twenty CRM frontend architecture emphasizes zero-runtime overhead and predictable state flow.

Global State with Jotai

Global state uses Jotai atoms instead of React Context or Redux. Primitive atoms hold core data (current user, selected objects), while derived atoms compose UI state without useEffect chains:

// packages/twenty-front/src/state/user.atom.ts
import { atom } from 'jotai';

export const currentUserAtom = atom<User | null>(null);

Zero-Runtime Styling with Linaria

Linaria provides CSS-in-JS that compiles away at build time, eliminating runtime style calculation overhead. Styles are written next to components but extracted to static CSS files.

Component Discipline

All components follow strict rules defined in CLAUDE.md:

  • Functional components only – No class components
  • Named exports only – No default exports
  • Strong TypeScript typing – No any types allowed

Source: CLAUDE.md – Key Development Principles

Development Workflow and Tooling

Twenty CRM architectural explanations include standardized commands for consistency across the monorepo:

Step Command Purpose
Setup bash packages/twenty-utils/setup-dev-env.sh Starts Postgres + Redis, creates DB, copies .env
Lint npx nx lint:diff-with-main twenty-server Fast lint against main branch
Type-check npx nx typecheck twenty-server Guarantees strict TS compliance
Build npx nx build twenty-server Compiles NestJS app
GraphQL generation npx nx run twenty-front:graphql:generate Sync GraphQL types from back-end schema
DB migrations npx nx run twenty-server:typeorm migration:generate … Generates migration files for entity changes

Source: CLAUDE.md – Development Workflow

Practical Code Examples

Importing Backend Modules

To extend the application, import modules into the root AppModule:

// packages/twenty-server/src/app.module.ts
import { Module } from '@nestjs/common';
import { WorkflowModule } from 'src/modules/workflow/workflow.module';

@Module({
  imports: [WorkflowModule, /* other modules */],
})
export class AppModule {}

Source: app.module.ts

Triggering Workflows Programmatically

The WorkflowTriggerWorkspaceService provides methods to initiate workflow versions:

// packages/twenty-server/src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service.ts
async triggerWorkflowVersion({
  workflowVersionId,
  workspaceId,
}: { workflowVersionId: string; workspaceId: string }) {
  const version = await this.workflowCommonWorkspaceService.getValidWorkflowVersionOrFail(
    await this.workflowVersionRepository.findOne({ where: { id: workflowVersionId } })
  );
  // ... schedule execution, create run, etc.
}

Source: workflow-trigger.workspace-service.ts

Scaffolding New Packages

To add a new package to the monorepo:

npx nx generate @nrwl/react:application my-plugin --directory=packages

This automatically integrates with the Nx project graph and inherits shared ESLint and TypeScript configurations.

Summary

  • Twenty CRM architectural explanations are centralized in CLAUDE.md and distributed throughout the source code, documenting a strictly modular design.
  • The Nx monorepo separates frontend (twenty-front), backend (twenty-server), and shared utilities (twenty-shared) into discrete packages with independent build pipelines.
  • Backend features use NestJS modules to enforce separation of concerns, as demonstrated by the Workflow feature's division into Trigger, Runner, and Status sub-modules.
  • Frontend architecture relies on Jotai for atomic state management and Linaria for zero-runtime CSS, following strict TypeScript and React functional component standards.
  • Development tooling uses Nx commands for linting, type-checking, GraphQL generation, and database migrations, ensuring consistency across the codebase.

Frequently Asked Questions

Where can I find Twenty CRM architectural documentation?

Twenty CRM maintains comprehensive architectural explanations in the CLAUDE.md file at the repository root, which covers the monorepo structure, tech stack, development workflow, and coding conventions. Additional architectural details are embedded as comments in key files like packages/twenty-server/src/app.module.ts and within module-specific directories under packages/twenty-server/src/modules/.

How does Twenty CRM organize its backend code?

The backend follows NestJS modular architecture, where each feature (Workflows, Contacts, Messaging) resides in its own directory under packages/twenty-server/src/modules/. Each module encapsulates its controllers, services, and providers, then imports into higher-level modules. For example, the Workflow module composes WorkflowTriggerModule and WorkflowStatusModule without containing business logic itself.

What state management does Twenty CRM use for the frontend?

Twenty CRM uses Jotai for global state management, implementing atomic state patterns where primitive atoms store core data (like current user) and derived atoms compute UI state. This approach eliminates prop drilling and reduces re-renders compared to React Context, while maintaining better TypeScript inference than Redux.

How can I add a new feature to Twenty CRM?

To add a feature, create a new NestJS module under packages/twenty-server/src/modules/ with its own services and controllers, then import it into packages/twenty-server/src/app.module.ts. For frontend components, add Jotai atoms in packages/twenty-front/src/state/ and UI components in packages/twenty-front/src/modules/. Use npx nx commands to generate types, run migrations, and ensure the feature integrates with the existing Twenty CRM architecture.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →