---
title: "ADR-021: Batch secret loading"
manual: "nr-vault"
version: "1.0"
permalink: "https://docs.typo3.org/permalink/netresearch/nr-vault:adr-021-batch-secret-loading@1.0"
source: "Developer/Adr/ADR-021-BatchSecretLoading.rst"
rendered: "2026-09-18T07:37:50+00:00"
---

# ADR-021: Batch secret loading {#adr-021-batch-secret-loading-1}

**Table of contents**

-   [Status](https://docs.typo3.org/permalink/netresearch/nr-vault:status@1.0)
-   [Date](https://docs.typo3.org/permalink/netresearch/nr-vault:date@1.0)
-   [Context](https://docs.typo3.org/permalink/netresearch/nr-vault:context@1.0)
-   [Decision](https://docs.typo3.org/permalink/netresearch/nr-vault:decision@1.0)
-   [Consequences](https://docs.typo3.org/permalink/netresearch/nr-vault:consequences@1.0)
-   [Related decisions](https://docs.typo3.org/permalink/netresearch/nr-vault:related-decisions@1.0)

## Status {#status}

Accepted

## Date {#date}

2026-03-28

## Context {#context}

`VaultService::list()` suffered from an N+1 query problem. For N secrets,
the implementation executed:

-   1 query to fetch the secret records
-   N queries to resolve each secret's MM group relations (allowed_groups)
-   N queries for additional per-secret metadata

This resulted in 1+2N database queries, meaning a vault with 50 secrets
required 101 queries for a single list operation. This scaled poorly and
caused noticeable latency in the backend module.

## Decision {#decision}

Add a `findAllWithFilters()` repository method that uses batch loading
to resolve all data in a constant number of queries:

-   **Query 1**: Fetch all matching secret records with filters applied.
-   **Query 2**: Batch-load all MM group relations for the fetched secrets
    in a single query using `WHERE uid_local IN (...)`.

Group assignments are then mapped to their respective secrets in PHP,
avoiding per-secret queries entirely.

## Consequences {#consequences}

### Positive {#positive}

-   **Constant query count**: Exactly 2 queries regardless of the number of
    secrets, eliminating the N+1 problem.
-   **Predictable performance**: List operations scale with result set size
    in PHP, not in database round-trips.
-   **Backward compatible**: The existing `list()` API is preserved;
    the optimization is internal to the repository layer.

### Negative {#negative}

-   **Memory usage**: All matching secrets and their group relations are
    loaded into memory at once. For very large vaults, pagination should
    be used.
-   **Complexity**: The batch MM resolution logic is more complex than the
    straightforward per-record approach.

## Related decisions {#related-decisions}

-   [ADR-005: Access control](https://docs.typo3.org/permalink/netresearch/nr-vault:adr-005-access-control@1.0) \- Group-based access control requiring MM resolution
-   [ADR-007: Secret metadata](https://docs.typo3.org/permalink/netresearch/nr-vault:adr-007-secret-metadata@1.0) \- Secret metadata model
