Files
twenty/packages/twenty-server
Weiko bd65dbd47a Cache metadata lookups during ORM result formatting (#23593)
## Context

Production profiling identified `formatResult` as a recurring CPU
hotspot on read paths, especially for list queries and nested relations.

The formatter receives one metadata snapshot for the complete result,
but previously rebuilt metadata-derived lookup structures for every
record. For each record, including recursively formatted relation
records, it rebuilt or rescanned:

- field name and join-column maps
- composite field property maps
- required composite properties
- date and date-time field collections

This metadata does not change while one result is being formatted, so
the repeated work scaled with the number of records without changing the
output. It also created short-lived allocations that added GC pressure
on busy server pods.

## What changed

- Create a private cache for each top-level `formatResult` invocation.
- Lazily derive formatter metadata once per object metadata ID.
- Reuse it across records in an array and recursively formatted
relations.
- Precompute required composite property names and date-time field
metadata.
- Remove the DATE post-processing pass, which assigned each value back
to itself.
- Keep the exported `formatResult` signature unchanged.

The cache is discarded when the formatting call returns.

## Why use a call-scoped cache

The derived structures are valid for the metadata maps passed to one
`formatResult` call. Keeping the cache local provides reuse for the
complete result batch without adding cross-request state, invalidation
rules, or another long-lived memory cache.

This also preserves existing callers and keeps recursive implementation
details private.

## Safety

- Formatting behavior and returned shapes are unchanged.
- Nested relation formatting still resolves metadata for each target
object type.
- Composite null and default handling, and DATE_TIME validation, are
unchanged.
- Metadata is recomputed for every top-level invocation, so a later
request cannot reuse data derived from an older metadata snapshot.
- No Redis, workspace-cache, database, or public API behavior changes.

## Expected impact

Metadata preparation now scales with the number of object types in a
result instead of the number of records. The largest benefit is expected
for list queries and nested relations, with lower CPU usage and fewer
short-lived allocations.

This is a targeted result-formatting optimization. It does not address
every source of API tail latency or retained cache memory.

## Validation

- Added a nested-relation regression test that verifies unchanged
output.
- The test verifies metadata resolution is bounded per object type
within one invocation and recomputed for a separate invocation.
- Focused formatter Jest suite.
- Existing chart relation-label Jest suite, 10 tests.
- Type-aware Oxlint.
- Oxfmt.
- `yarn nx typecheck twenty-server`.
2026-07-30 16:31:44 +00:00
..