# Core NestJS Modules & API Surface

> Server-side domain modules: auth (JWT, SSO), billing, messaging, calendar, workflow, workspace, and the GraphQL API layers (code-first resolvers, subscriptions, dataloaders). How NestJS modules are registered in app.module.ts and how the GraphQL Yoga gateway is configured.

- Repository: twentyhq/twenty
- GitHub: https://github.com/twentyhq/twenty
- Human wiki: https://grok-wiki.com/public/wiki/twentyhq-twenty-7ed82e5a21f6
- Complete Markdown: https://grok-wiki.com/public/wiki/twentyhq-twenty-7ed82e5a21f6/llms-full.txt

## Source Files

- `packages/twenty-server/src/engine/core-modules/core-engine.module.ts`
- `packages/twenty-server/src/engine/core-modules/auth`
- `packages/twenty-server/src/engine/core-modules/billing`
- `packages/twenty-server/src/modules/messaging`
- `packages/twenty-server/src/modules/workflow`
- `packages/twenty-server/src/engine/api`
- `packages/twenty-server/src/engine/subscriptions`
- `packages/twenty-server/src/engine/dataloaders`

---

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:

- [packages/twenty-server/src/app.module.ts](packages/twenty-server/src/app.module.ts)
- [packages/twenty-server/src/engine/core-modules/core-engine.module.ts](packages/twenty-server/src/engine/core-modules/core-engine.module.ts)
- [packages/twenty-server/src/engine/core-modules/auth/auth.module.ts](packages/twenty-server/src/engine/core-modules/auth/auth.module.ts)
- [packages/twenty-server/src/engine/core-modules/auth/strategies/jwt.auth.strategy.ts](packages/twenty-server/src/engine/core-modules/auth/strategies/jwt.auth.strategy.ts)
- [packages/twenty-server/src/engine/core-modules/billing/billing.module.ts](packages/twenty-server/src/engine/core-modules/billing/billing.module.ts)
- [packages/twenty-server/src/engine/core-modules/workflow/workflow-api.module.ts](packages/twenty-server/src/engine/core-modules/workflow/workflow-api.module.ts)
- [packages/twenty-server/src/engine/core-modules/sso/sso.module.ts](packages/twenty-server/src/engine/core-modules/sso/sso.module.ts)
- [packages/twenty-server/src/engine/api/graphql/core-graphql-api.module.ts](packages/twenty-server/src/engine/api/graphql/core-graphql-api.module.ts)
- [packages/twenty-server/src/engine/api/graphql/metadata-graphql-api.module.ts](packages/twenty-server/src/engine/api/graphql/metadata-graphql-api.module.ts)
- [packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.module.ts](packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.module.ts)
- [packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.service.ts](packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.service.ts)
- [packages/twenty-server/src/engine/subscriptions/subscriptions.module.ts](packages/twenty-server/src/engine/subscriptions/subscriptions.module.ts)
- [packages/twenty-server/src/engine/dataloaders/dataloader.module.ts](packages/twenty-server/src/engine/dataloaders/dataloader.module.ts)
- [packages/twenty-server/src/engine/dataloaders/dataloader.service.ts](packages/twenty-server/src/engine/dataloaders/dataloader.service.ts)
</details>

# Core NestJS Modules & API Surface

The Twenty server backend is a NestJS application organized around a two-tier module hierarchy: a root `AppModule` that wires together infrastructure concerns, and a large `CoreEngineModule` that aggregates all domain-specific feature modules. Understanding this structure is essential for adding new server capabilities, debugging request flows, and navigating the GraphQL and REST API layers.

This page covers how domain modules (auth, billing, messaging, calendar, workflow, workspace, SSO) are declared and composed, how the three GraphQL Yoga endpoints are registered and configured, what Yoga plugins are active, how subscriptions and dataloaders integrate, and where REST and MCP API surface are defined.

---

## Module Hierarchy Overview

```text
AppModule  (packages/twenty-server/src/app.module.ts)
├── GraphQLModule (Yoga) × 3  — core / metadata / admin-panel
├── TwentyORMModule            — custom TypeORM integration
├── CoreEngineModule           — all domain feature modules
├── ModulesModule              — business-logic workspace modules
├── CoreGraphQLApiModule       — workspace schema factory + SDL
├── MetadataGraphQLApiModule   — metadata schema endpoint
├── AdminPanelGraphQLApiModule — admin schema endpoint
├── RestApiModule              — REST API surface
├── McpModule                  — MCP protocol endpoint
├── DataloaderModule           — per-request DataLoaders
├── SubscriptionsModule        — (via CoreEngineModule)
└── MiddlewareModule           — request middleware
```

`CoreEngineModule` is the central aggregator; it has no business logic of its own — it just imports and re-exports all domain modules.

---

## AppModule: Root Wiring

`AppModule` (`packages/twenty-server/src/app.module.ts`) is the NestJS entry point. Its key responsibilities:

### GraphQL Yoga Gateway Registration

Three independent `GraphQLModule.forRootAsync` calls register three separate GraphQL Yoga endpoints, each with its own path, schema, and plugin set:

| Module | Path | Schema scope |
|---|---|---|
| `GraphQLModule` in `AppModule` | `/graphql` | Core (resolvers from `CoreEngineModule`) |
| `MetadataGraphQLApiModule` | `/metadata` | Metadata (object/field definitions) |
| `AdminPanelGraphQLApiModule` | `/admin-panel` | Admin panel |

The core `/graphql` endpoint is configured via `GraphQLConfigService` using the `YogaDriver`:

```typescript
// packages/twenty-server/src/app.module.ts:52-56
GraphQLModule.forRootAsync<YogaDriverConfig>({
  driver: YogaDriver,
  imports: [GraphQLConfigModule, MetricsModule, DataloaderModule],
  useClass: GraphQLConfigService,
}),
```

Sources: [packages/twenty-server/src/app.module.ts:52-56]()

### Middleware Pipeline

`AppModule.configure()` applies two key middleware chains:

1. **GraphQL/Metadata/Admin routes** (`/graphql`, `/metadata`, `/admin-panel`): `GraphQLHydrateRequestFromTokenMiddleware` → `WorkspaceAuthContextMiddleware`. The hydrate middleware extracts the JWT and attaches user + workspace to `req`; the auth-context middleware validates workspace activation status.
2. **REST routes** (`/rest/*path`): `RestCoreMiddleware` → `WorkspaceAuthContextMiddleware`.
3. **MCP route** (`/mcp`): `McpMethodGuardMiddleware` only.

Sources: [packages/twenty-server/src/app.module.ts:114-145]()

---

## GraphQL Yoga Configuration

`GraphQLConfigService` (`packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.service.ts`) implements `GqlOptionsFactory<YogaDriverConfig>` and is the single source of truth for the core GraphQL endpoint's behavior.

### Yoga Plugins

The following plugins are always active:

| Plugin | Purpose |
|---|---|
| `useDirectExecution` | Short-circuits resolution for internally issued queries (avoids HTTP round-trips) |
| `useGraphQLErrorHandlerHook` | Normalizes and forwards errors to metrics + exception handler |
| `useDisableIntrospectionAndSuggestionsForUnauthenticatedUsers` | Blocks schema introspection in production for unauthenticated callers |
| `useValidateGraphqlQueryComplexity` | Enforces `GRAPHQL_MAX_FIELDS` and `GRAPHQL_MAX_ROOT_RESOLVERS` limits; rejects duplicate root resolvers |
| `useSentryTracing` | Added conditionally when Sentry is initialized |

The schema is built in code-first mode with `autoSchemaFile: true`, scoped to `CoreEngineModule` resolvers via `include: [CoreEngineModule]` and `resolverSchemaScope: 'core'`. The `JSON` scalar is registered globally.

Per-request DataLoaders are injected into the GraphQL context through the context factory:

```typescript
// packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.service.ts
context: () => ({
  loaders: this.dataloaderService.createLoaders(),
}),
```

In development mode, an Apollo Playground renderer is mounted at the endpoint.

Sources: [packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.service.ts:40-95]()

### Metadata GraphQL Endpoint

`MetadataGraphQLApiModule` registers a second Yoga instance that serves the metadata schema (object metadata, field metadata, relations). It uses the same `YogaDriver` and reuses `DataloaderModule` and `MetricsModule`. The factory function is `metadataModuleFactory`. The metadata schema includes resolvers from `MetadataEngineModule`.

Sources: [packages/twenty-server/src/engine/api/graphql/metadata-graphql-api.module.ts]()

---

## CoreEngineModule: Domain Module Registry

`CoreEngineModule` (`packages/twenty-server/src/engine/core-modules/core-engine.module.ts`) imports ~65 modules and re-exports a smaller set for consumption by peer modules. It is imported by `AppModule` and the `GraphQLConfigModule`.

Key domain groupings registered here:

### Auth & Identity

- **`AuthModule`** — central authentication module: JWT strategy, SAML strategy, sign-in/up flows, OAuth controllers, SSO connection services, token issuance
- **`WorkspaceSSOModule`** — SAML/OIDC SSO resolver and service (`SSOService`, `SSOResolver`)
- **`AppTokenModule`**, **`ApiKeyModule`** — application-level token management
- **`ImpersonationModule`** — admin impersonation support
- **`TwoFactorAuthenticationModule`** — TOTP/2FA (declared inside `AuthModule`)

Sources: [packages/twenty-server/src/engine/core-modules/core-engine.module.ts:21-58]()

### Billing (Enterprise)

- **`BillingModule`** — Stripe-backed subscription management. Provides `BillingResolver`, `BillingSubscriptionService`, `BillingPortalWorkspaceService`, entitlement checks, credit rollover, usage caps, and workspace-member listeners. Entity models: `BillingSubscriptionEntity`, `BillingCustomerEntity`, `BillingEntitlementEntity`, `BillingProductEntity`, `BillingPriceEntity`, `BillingMeterEntity`.
- **`BillingWebhookModule`** — handles inbound Stripe webhook events
- **`AppBillingModule`** — billing for marketplace applications
- **`AiBillingModule`** — billing for AI model usage
- **`BillingGraphqlApiExceptionFilter`** — registered as `APP_FILTER` to translate billing exceptions into structured GraphQL errors

Sources: [packages/twenty-server/src/engine/core-modules/billing/billing.module.ts:45-90](), [packages/twenty-server/src/engine/core-modules/core-engine.module.ts:170-175]()

### Messaging & Calendar

- **`TimelineMessagingModule`** — exposes messaging timeline queries for the GraphQL API
- **`MessagingWebhooksModule`** — inbound webhooks for email providers
- **`TimelineCalendarEventModule`** — calendar event timeline queries
- **`ImapSmtpCaldavModule`** — IMAP/SMTP/CalDAV connection management
- **`ChannelSyncModule`**, **`SendEmailModule`** — channel sync state and outbound email dispatch (imported from `src/modules/`)

Sources: [packages/twenty-server/src/engine/core-modules/core-engine.module.ts:49-50, 75-77, 129-131]()

### Workflow

`WorkflowApiModule` (`packages/twenty-server/src/engine/core-modules/workflow/workflow-api.module.ts`) is the GraphQL-facing workflow surface. It declares:

- **Resolvers**: `WorkflowTriggerResolver`, `WorkflowBuilderResolver`, `WorkflowVersionStepResolver`, `WorkflowVersionEdgeResolver`, `WorkflowVersionResolver`
- **Controller**: `WorkflowTriggerController` (REST webhook entry point for external triggers)
- **Imports**: `WorkflowTriggerModule`, `WorkflowBuilderModule`, `WorkflowRunnerModule`, `WorkflowRunModule`, `WorkflowCommonModule`, `WorkflowVersionModule` (from `src/modules/workflow/`)

Sources: [packages/twenty-server/src/engine/core-modules/workflow/workflow-api.module.ts]()

### Workspace

- **`WorkspaceModule`** — workspace CRUD, activation lifecycle, provisioning
- **`WorkspaceInvitationModule`** — invitation flow
- **`UserModule`** — user entity, profile, preferences
- **`UserWorkspaceModule`** — user-workspace membership
- **`AdminPanelModule`** — admin-restricted operations

### Infrastructure Modules

| Module | Role |
|---|---|
| `FeatureFlagModule` | Runtime feature flag evaluation |
| `CacheStorageModule` | Redis-backed cache abstraction |
| `RedisClientModule` | Shared Redis client |
| `MessageQueueModule` | BullMQ job queue (registered async with factory) |
| `FileStorageModule` | S3 / local file storage abstraction |
| `EmailModule` | Transactional email dispatch |
| `MetricsModule` | Prometheus-style metrics |
| `ExceptionHandlerModule` | Sentry integration and error normalization |
| `LoggerModule` | Structured logging |
| `SearchModule` | Full-text search |
| `TelemetryModule` | Usage telemetry |
| `EventEmitterModule` (NestJS) | In-process event bus with wildcard support |
| `TwentyConfigModule` | Type-safe environment configuration |

Dynamic modules follow the `forRootAsync` pattern with factory functions and explicit dependency injection:

```typescript
// packages/twenty-server/src/engine/core-modules/core-engine.module.ts:133-148
MessageQueueModule.registerAsync({
  useFactory: messageQueueModuleFactory,
  inject: [TwentyConfigService, RedisClientService, MetricsService],
}),
ExceptionHandlerModule.forRootAsync({
  useFactory: exceptionHandlerModuleFactory,
  inject: [TwentyConfigService, HttpAdapterHost],
}),
```

Sources: [packages/twenty-server/src/engine/core-modules/core-engine.module.ts:83-169]()

---

## Auth Module Deep Dive

`AuthModule` is one of the most complex modules. Its structure:

### JWT Strategy

`JwtAuthStrategy` (`packages/twenty-server/src/engine/core-modules/auth/strategies/jwt.auth.strategy.ts`) extends `PassportStrategy(Strategy, 'jwt')`. Key behaviors:
- Uses a dynamic `SecretOrKeyProvider` rather than a static secret, delegating key resolution to `JwtWrapperService.resolveVerificationKey()` — this allows multiple signing keys and algorithm negotiation.
- Validates the resolved token against `JWT_SUPPORTED_VERIFY_ALGORITHMS`.
- Resolves workspace and user context from the validated payload, checking workspace activation status and permission flags.

### SSO / SAML Strategy

`SamlAuthStrategy` and `AuthSsoService` handle SAML assertion validation. The `SSOAuthController` is the ACS endpoint. `WorkspaceSSOModule` (an enterprise-licensed module) owns `SSOService` and the `SSOResolver` for managing identity providers via GraphQL.

### OAuth Controllers

`AuthModule` declares five REST controllers:

| Controller | Purpose |
|---|---|
| `GoogleAuthController` | Google OAuth sign-in callback |
| `MicrosoftAuthController` | Microsoft OAuth sign-in callback |
| `GoogleAPIsAuthController` | Google API scope grant callback |
| `MicrosoftAPIsAuthController` | Microsoft API scope grant callback |
| `OAuthPropagatorController` | Propagates OAuth tokens to workspaces |
| `SSOAuthController` | SAML SSO assertion consumer service |
| `ConnectionProviderOAuthController` | Marketplace app OAuth callbacks |

Sources: [packages/twenty-server/src/engine/core-modules/auth/auth.module.ts:133-141]()

### Token Services

`TokenModule` (imported by `AuthModule`) provides:
- `AccessTokenService` — short-lived JWT for API access
- `RefreshTokenService` — long-lived refresh flow
- `LoginTokenService` — one-time login link tokens
- `TransientTokenService` — temporary cross-step tokens used in OAuth flows

---

## Subscriptions Module

`SubscriptionsModule` (`packages/twenty-server/src/engine/subscriptions/subscriptions.module.ts`) is declared `@Global()` and provides real-time push infrastructure:

- **`EventStreamResolver`** — GraphQL subscription resolver (`Subscription` decorator)
- **`EventStreamService`** — manages active subscription channels
- **`SubscriptionService`** — coordinates subscription lifecycle
- **`ObjectRecordEventPublisher`** — publishes CRUD events for workspace objects into the event stream
- **`MetadataEventPublisher`** / **`MetadataEventEmitter`** — publishes metadata change events (object/field schema changes)
- **`MetadataEventsToDbListener`** — persists metadata events to the database
- **`WorkspaceEventBroadcaster`** — fans out workspace events to connected subscribers

Backing store is Redis via `CacheStorageModule`. The module imports `WorkspaceCacheModule` for workspace schema lookups and `WorkspaceManyOrAllFlatEntityMapsCacheModule` for flat entity resolution during event fan-out.

Sources: [packages/twenty-server/src/engine/subscriptions/subscriptions.module.ts]()

---

## Dataloaders

`DataloaderModule` / `DataloaderService` (`packages/twenty-server/src/engine/dataloaders/`) implement the [DataLoader pattern](https://github.com/graphql/dataloader) for N+1 query prevention in the GraphQL resolvers.

`DataloaderService.createLoaders()` is called once per request from the Yoga context factory. It returns an `IDataloaders` object containing named `DataLoader<K, V>` instances for:

- Field metadata resolution by workspace
- Object metadata resolution by workspace
- Relation metadata (including morph/polymorphic relations)
- View fields, filters, sorts, groups, field groups, filter groups
- Index metadata

The loaders use `WorkspaceManyOrAllFlatEntityMapsCacheModule` as the backing cache layer — they batch IDs across a single tick, look up from the flat entity cache, and return resolved DTOs (e.g. `FieldMetadataDTO`, `ObjectMetadataDTO`, `RelationDTO`).

Sources: [packages/twenty-server/src/engine/dataloaders/dataloader.module.ts](), [packages/twenty-server/src/engine/dataloaders/dataloader.service.ts:1-60]()

---

## API Surface Summary

```text
HTTP Routes
├── POST /graphql        — Core GraphQL Yoga (workspace data)
├── POST /metadata       — Metadata GraphQL Yoga (schema definitions)
├── POST /admin-panel    — Admin GraphQL Yoga
├── /rest/*path          — REST API (TwentyORM-backed)
└── /mcp                 — Model Context Protocol endpoint

GraphQL Schema Scopes
├── core                 → CoreEngineModule resolvers (code-first, autoSchemaFile)
├── metadata             → MetadataEngineModule resolvers
└── admin-panel          → AdminPanelGraphQLApiModule resolvers
```

All three GraphQL endpoints share the same `YogaDriver`. The core endpoint's `resolverSchemaScope: 'core'` and `include: [CoreEngineModule]` ensures only domain resolvers declared inside `CoreEngineModule` appear in the generated schema.

---

## Summary

Twenty's server architecture uses a clear two-tier NestJS module pattern: `AppModule` owns infrastructure bootstrapping (Yoga instances, ORM, middleware), while `CoreEngineModule` is a pure aggregator of ~65 domain modules covering auth (JWT + SAML + OAuth), billing (Stripe), messaging, calendar, workflow, workspace management, and SSO. The GraphQL Yoga gateway runs three independent endpoint instances, each with its own schema scope and plugin pipeline. Query complexity limits, introspection guards, Sentry tracing, and per-request DataLoaders are all wired through the central `GraphQLConfigService`. Real-time subscriptions are served via a global `SubscriptionsModule` backed by Redis pub/sub.
