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

> Explore Twenty CRM's monorepo architecture and feature design. Get deep architectural explanations for its modular NestJS backend, React frontend, and Nx monorepo structure.

- Repository: [Twenty/twenty](https://github.com/twentyhq/twenty)
- Tags: architecture
- Published: 2026-03-27

---

**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`](https://github.com/twentyhq/twenty/blob/main/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](https://github.com/twentyhq/twenty/blob/main/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](https://github.com/twentyhq/twenty/blob/main/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`](https://github.com/twentyhq/twenty/blob/main/workflow.module.ts) only wires the essential sub-modules:

```typescript
// 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](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/modules/workflow/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:

- [`packages/twenty-server/src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service.ts)
- [`packages/twenty-server/src/modules/workflow/workflow-runner/workspace-services/workflow-runner.workspace-service.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/modules/workflow/workflow-runner/workspace-services/workflow-runner.workspace-service.ts)

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:

```typescript
// 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`](https://github.com/twentyhq/twenty/blob/main/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](https://github.com/twentyhq/twenty/blob/main/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](https://github.com/twentyhq/twenty/blob/main/CLAUDE.md#development-workflow)**

## Practical Code Examples

### Importing Backend Modules

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

```typescript
// 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](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/app.module.ts)**

### Triggering Workflows Programmatically

The `WorkflowTriggerWorkspaceService` provides methods to initiate workflow versions:

```typescript
// 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](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service.ts)**

### Scaffolding New Packages

To add a new package to the monorepo:

```bash
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`](https://github.com/twentyhq/twenty/blob/main/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`](https://github.com/twentyhq/twenty/blob/main/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`](https://github.com/twentyhq/twenty/blob/main/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`](https://github.com/twentyhq/twenty/blob/main/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.