Skip to content

Prevent metadata schema leakage into /graphql; disable GraphQL auto-discovery & speed up NestJS boot #17638

@FelixMalfait

Description

@FelixMalfait

Summary

The /graphql endpoint currently exposes metadata resolvers/types that should only appear under /metadata. This is caused by GraphQL auto‑discovery scanning a broad module tree, which also contributes to slower NestJS boot times.

We should disable auto‑discovery for core GraphQL and move to explicit schema construction, while keeping resolvers co‑located with services. For metadata, we should also create an explicit schema from a central resolver list.

Background / Evidence

  • Core GraphQL is configured with autoSchemaFile: true and include: [CoreEngineModule], which causes Nest/Yoga to scan the entire module graph for resolvers. That module graph includes metadata modules, so metadata resolvers get pulled into /graphql. (packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.service.ts; packages/twenty-server/src/engine/core-modules/core-engine.module.ts)
  • The /metadata endpoint uses the same auto‑discovery pattern via autoSchemaFile and include, pointing at MetadataGraphQLApiModule, which itself imports MetadataEngineModule (thereby scanning metadata resolvers). (packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts; packages/twenty-server/src/engine/api/graphql/metadata-graphql-api.module.ts)
  • We already build the core workspace schema explicitly using WorkspaceSchemaFactory + makeExecutableSchema, so core GraphQL can work without discovery if we stop enabling it in config. (packages/twenty-server/src/engine/api/graphql/workspace-schema.factory.ts)

Goals

  1. Stop /graphql from exposing metadata schema.
  2. Remove GraphQL auto‑discovery for the core endpoint and rely on explicit schema building.
  3. Keep resolvers close to services (no per‑resolver modules).
  4. Improve startup time by avoiding deep module graph scans.

Proposed Approach

✅ Core /graphql (explicit only)

  • Remove autoSchemaFile: true and include: [CoreEngineModule] from core GraphQL config.
  • Ensure the schema comes only from the existing conditionalSchema path that uses WorkspaceSchemaFactory.
  • This eliminates Nest’s resolver scanning for core GraphQL entirely, preventing metadata bleed‑through and speeding startup.

Files involved:

  • packages/twenty-server/src/engine/api/graphql/graphql-config/graphql-config.service.ts (remove auto‑discovery config, rely on conditional schema).
  • packages/twenty-server/src/engine/api/graphql/workspace-schema.factory.ts (already builds schema explicitly; no changes expected unless needed).

✅ Metadata /metadata (explicit resolver list, no auto‑discovery)

  • Keep resolvers where they are, but create a single centralized resolver list and build the metadata schema explicitly.
  • Replace autoSchemaFile + include with an explicit schema build (e.g., buildSchema or Nest GraphQLSchemaFactory, depending on existing stack).
  • Import service modules as needed for DI, but do not scan the module graph for resolvers.

Files involved:

  • packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts (remove autoSchemaFile & include, provide explicit schema).
  • packages/twenty-server/src/engine/api/graphql/metadata-graphql-api.module.ts (keep module wiring; update to use explicit schema instead of auto‑discovery).

Acceptance Criteria

  • /graphql introspection shows no metadata types or resolvers.
  • /metadata continues to expose all metadata types/resolvers as before.
  • Boot time improves or at least no longer worsens due to GraphQL scanning.
  • No per‑resolver modules introduced; resolvers remain close to services.

Optional Tests / Checks

  • Add an integration test that introspects /graphql and asserts metadata types (e.g., ObjectMetadata, FieldMetadata) are absent.
  • Add a complementary test for /metadata asserting those types are present.

Notes

This change doesn’t require reorganizing resolvers into per‑resolver modules. The main shift is from auto‑discovery to explicit schema composition, which also reduces Nest’s module scanning overhead and makes schema boundaries explicit.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status

🔖 Planned

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions