PAS7 Studio

Tecnologia

Il problema del Request Context in NestJS: DI request-scoped vs AsyncLocalStorage (ALS) — una guida pratica per la produzione (2026)

Una guida approfondita e basata su fonti al problema più doloroso in NestJS: request context (utente, tenant, correlation IDs, tracing) senza trasformare il grafo DI in REQUEST scope. Include confronti, pattern reali e un percorso pratico con @pas7/nestjs-request-context.

08 Feb 2026· 18 min read
Request context in NestJS: DI request-scoped vs AsyncLocalStorage (ALS), logging e tracing

Cosa otterrai da questo articolo

Non è un post “teorico”. È una guida pratica applicabile in un vero codebase NestJS — con fonti verificate e un framework decisionale chiaro.

  • Che cosa significa davvero “request context” in NestJS (e perché fa male). [1][2][3]

  • Perché i provider REQUEST-scoped sembrano facili — ma spesso diventano una trappola di performance e architettura. [1]

  • Come AsyncLocalStorage (ALS) risolve il pain core (e dove può ancora fallire). [2][3]

  • Come lo fanno le aziende: correlation IDs, tracing, propagazione OpenTelemetry, confini di contesto sicuri. [4][5][6][7]

  • Un confronto curato dei pacchetti più rilevanti (con pro/contro e casi d’uso ideali). [8][9][10][11][12]

  • Una guida da produzione + pattern di codice copiabili (HTTP + code + microservizi). [2][6][7]

  • Dove si colloca @pas7/nestjs-request-context e quando è una scelta competitiva. [10]

Il problema più doloroso in NestJS: request context senza danni collaterali

“Request context” è tutto ciò che vuoi poter leggere in profondità nei servizi senza infilare parametri ovunque: utente corrente, tenant, permessi, request ID, trace IDs, handle transazionale, locale, feature flags e altro.

In NestJS di solito finisci in uno di questi esiti:

- Passi il contesto esplicitamente come parametri (affidabile, ma rumoroso e difficile da mantenere).

- Usi provider REQUEST-scoped (API semplice, ma può rendere una grossa parte dell’app instanziata per request). [1]

- Usi contesto basato su AsyncLocalStorage (punti di invocazione puliti, provider singleton, ma serve setup corretto e consapevolezza dei casi limite). [2][3]

Perché la DI REQUEST-scoped diventa una trappola (e perché i team se ne pentono)

NestJS lo dice chiaramente: i provider request-scoped aggiungono overhead perché le istanze vengono create per request e — cosa più importante — lo scope “si propaga” attraverso le dipendenze. [1]

Due citazioni importanti quando disegni l’architettura:

> “Any provider that relies on a request-scoped provider automatically adopts a request scope, and this behavior cannot be altered.” [1]

> “Using request-scoped providers will have an impact on application performance... it will still have to create an instance of your class on each request.” [1]

Ecco come le app reali finiscono nei guai: un singolo “datasource / logger / context” request-scoped diventa dipendenza radice e improvvisamente controller, service e repository vengono ricreati per request. Nest cita anche le app multi-tenant come scenario comune. [1]

Sì, Nest menziona che l’impatto può essere “~5% latency-wise” in un’app ben progettata — ma il costo vero spesso è architetturale: diventa più difficile ragionare su lifetime, caching e sulla “forma” del tuo albero DI. [1]

AsyncLocalStorage in un minuto: perché mappa perfettamente il request context

Node.js AsyncLocalStorage è essenzialmente “thread-local storage per codice async”: ti permette di associare uno stato a una catena di esecuzione (promise/callback) e leggerlo dopo senza passare parametri. [3]

La doc di Node raccomanda AsyncLocalStorage rispetto a implementazioni fai-da-te basate su async_hooks, descrivendolo come performante e memory-safe. [3]

Ma non è magia. La perdita di contesto può ancora accadere in “rare situazioni”, specialmente con API a callback o thenable custom — Node consiglia promisify o AsyncResource per bindare correttamente il contesto di esecuzione. [3]

Quindi la domanda diventa: possiamo avvolgere in modo affidabile il lifecycle della request Nest così che tutto a valle veda lo stesso store? NestJS risponde: sì — via middleware / punto di ingresso del lifecycle. [2]

Direzione ufficiale NestJS: ALS come alternativa al REQUEST scope

NestJS posiziona esplicitamente ALS come modo per propagare stato senza passare parametri e come alternativa ai provider REQUEST-scoped “e alcune delle loro limitazioni”. [2]

Idea core: avvolgere la request presto (middleware) con als.run(store, () => next()). Poi qualsiasi provider può leggere dallo store ALS più tardi.

Esempio minimale in stile NestJS (semplificato dalla ricetta ufficiale): [2]

TS
import { Module, MiddlewareConsumer, NestModule } from '@nestjs/common';
import { AsyncLocalStorage } from 'node:async_hooks';

const als = new AsyncLocalStorage<{ requestId: string; userId?: string }>();

@Module({})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply((req: any, _res: any, next: () => void) => {
        const store = {
          requestId: String(req.headers['x-request-id'] ?? crypto.randomUUID()),
          userId: req.headers['x-user-id'] ? String(req.headers['x-user-id']) : undefined,
        };
        als.run(store, () => next());
      })
      .forRoutes('*path');
  }
}

Questo è il pattern “core pulito”. I setup da produzione aggiungono: parsing sicuro degli header, echo dell’header in response, correlazione con tracing, propagazione code/microservizi e testing.

Come lo fanno davvero le aziende: correlation IDs + tracing + propagazione sicura

Nei sistemi di produzione, il request context non riguarda solo “l’utente corrente”. I driver più comuni sono osservabilità e incident response: servono log, trace e metriche correlabili in modo affidabile tra servizi.

È esattamente ciò di cui tratta la propagazione del contesto OpenTelemetry: spostare trace/span context attraverso confini di processo e rete (di default usando header W3C Trace Context come traceparent). [6][7]

Due takeaway pratici dal mondo enterprise:

- Puoi tenere il contesto “in-process” in ALS, ma oltre i confini devi propagare esplicitamente (header HTTP, metadata messaggi, ecc.). [6][7]

- Non mettere dati sensibili nella propagazione cross-service. OpenTelemetry avverte esplicitamente di non inserire segreti/PII in baggage o key-values propagati. [6]

Nota operativa 2026 da non ignorare se dipendi pesantemente da ALS (direttamente o via APM/tracing): Node.js ha rilasciato una mitigazione per un edge case DoS legato ad async_hooks/ALS a gennaio 2026 e raccomanda l’upgrade a versioni patchate. Team APM e OTel hanno pubblicato guidance e contesto. [4][5]

Panorama pacchetti (2026): cosa esiste, cosa è solido, cosa è rischioso

Sotto trovi un confronto ad alto segnale dei pacchetti usati da team reali per risolvere il request context in NestJS. L’obiettivo non è “chi ha più stelle”, ma: correttezza, ergonomia, integrazioni e quanto evita REQUEST scope.

Tabella comparativa rapida

PackageCore approachBest forKey trade-offs
nestjs-clsALS + ClsService + Proxy Providers + pluginscontext completo + transazionipiù astrazione; API surface da imparare
@pas7/nestjs-request-contextALS + typed keys + decorators + adaptersrequest context strict, leggero e tipizzatoecosistema più nuovo; dipende dalle integrazioni che ti servono
@medibloc/nestjs-request-contextrequest context ALS-basedcontesto ALS semplicescope più stretto rispetto a nestjs-cls
nestjs-pino (parte context)integrazione logging via ALSlogging contestuale con Pinofocalizzato sul logging (non un framework generale)
DIY (ricetta Nest)ALS “raw”minimale + pieno controlloti prendi edge case + testing

Ora i dettagli con fonti:

- nestjs-cls si presenta come modulo continuation-local storage per NestJS basato su AsyncLocalStorage, con use case come request ID tracking, multi-tenancy e propagazione di transazioni senza passare parametri espliciti. [8]

- nestjs-pino documenta un argomento chiave spesso ripetuto: evitare provider REQUEST-scoped per cali di performance, usando AsyncLocalStorage per logger legati alla request. [11]

- La ricetta ufficiale Nest riconosce ALS come alternativa valida al REQUEST scope — ma dice anche che NestJS non offre un’astrazione built-in, quindi o implementi tu o usi una libreria. [2]

Deep dive: quando `nestjs-cls` è la scelta migliore

Se i tuoi bisogni di contesto sono ampi (multi-tenancy + transazioni + proxy providers + “request context dove REQUEST scope non è supportato”), nestjs-cls è spesso la toolbox più completa. Le sue docs enfatizzano use case ampi e menzionano esplicitamente l’evitare approcci REQUEST-scoped “scomodi”. [8]

Motivo frequente di adozione: propagare transazioni senza passare un oggetto transazione ovunque, più un ecosistema di plugin supportati attorno a questo pattern. [8]

Se sei già dentro quell’ecosistema, cambiare dopo raramente conviene — ma se ti servono solo 2–3 campi (requestId, userId, tenantId) potresti volere qualcosa di più piccolo.

Dove si colloca `@pas7/nestjs-request-context` (e quando è competitivo)

@pas7/nestjs-request-context è allineato direttamente a questo problema: fornire request context via AsyncLocalStorage mantenendo singleton il tuo albero DI, con forte focus sulla sicurezza dei tipi tramite typed keys e un’ergonomia pulita per NestJS. [10]

Perché è particolarmente rilevante per questo articolo:

- ContextKey<T> tipizzato per i valori del contesto (meno “magic keys” stringly-typed). [10]

- Ergonomia NestJS: decorator (es. parameter decorators) per leggere contesto senza plumbing. [10]

- Adapter HTTP per Express e Fastify in ambienti NestJS. [10]

- Posizionamento esplicito contro l’approccio REQUEST-scope per performance/architettura. [10]

Caveat (onestà): il repo nota che usare l’adapter Fastify fuori da NestJS è limitato per incompatibilità Fastify + AsyncLocalStorage, quindi trattalo come NestJS-first. [10]

Setup pratico: una guida production-friendly (pattern copia/incolla)

Questa sezione è la checklist “fallo bene”: dove inizializzare il contesto, cosa salvare, come propagare a code/microservizi e come testarlo per evitare leak di contesto.

Campi di contesto consigliati (default pratico)

- requestId: correlation ID stabile; rimandalo come x-request-id in response.

- userId: identificatore interno utente (evita email/telefono).

- tenantId: se multi-tenant.

- traceId / spanId: se usi tracing (o derivali dal contesto OTel).

- authLevel / role: se serve per decisioni di autorizzazione (preferisci check espliciti nei flussi critici).

Pattern A: DIY ALS minimale (ottimo se vuoi full control)

Usa l’approccio middleware della ricetta Nest e implementa un wrapper piccolo (con test). [2]

Pattern B: Usa nestjs-cls quando ti serve l’ecosistema

Se ti servono plugin di propagazione transazioni e proxy provider pattern, nestjs-cls è una scelta forte. [8]

Pattern C: Usa @pas7/nestjs-request-context per typed keys strict + surface area snella

Se ti serve un request context pulito e tipizzato (requestId/userId/tenantId + poco altro) e valorizzi un layer NestJS-first con adapter, la libreria PAS7 è una buona scelta. [10]

Punto di inizializzazione

Lifecycle precoce

Inizializza il contesto il prima possibile (middleware è la scelta più sicura per HTTP in Nest). La ricetta Nest usa proprio il middleware. [2]

DI singleton

Evita REQUEST scope

I provider REQUEST-scoped possono far propagare lo scope nelle dipendenze e aggiungere overhead di instanziazione per request. Nest lo evidenzia. [1]

Propagazione cross-service

Esplicita

ALS funziona solo in-process. Tra servizi, propaga con header/metadata messaggi. OTel usa di default W3C Trace Context (traceparent). [6][7]

Sicurezza

Niente segreti nel contesto

Non propagare dati sensibili in contesto/baggage. OTel avverte esplicitamente su segreti/PII in campi propagati tipo baggage. [6]

Diagramma: request entra nel middleware -> ALS store -> servizi -> logger -> db -> propagazione coda

Flusso request-context sicuro: inizializza presto, leggi ovunque, propaga esplicitamente oltre i confini

Section pas7-quickstart screenshot

Pattern di codice: `@pas7/nestjs-request-context` (typed keys + accesso ergonomico)

Sotto trovi pattern illustrativi basati sull’approccio della libreria (typed ContextKey<T>, ergonomia Nest-first, adapter). Verifica sempre i nomi esatti delle API nel repo prima di fissare l’uso in produzione. [10]

1) Definisci typed keys (un modulo/pacchetto condiviso)

TS
import { ContextKey } from '@pas7/nestjs-request-context';

export const REQUEST_ID = new ContextKey<string>('requestId');
export const USER_ID = new ContextKey<string | undefined>('userId');
export const TENANT_ID = new ContextKey<string | undefined>('tenantId');

2) Inizializza nel middleware (entry point HTTP)

TS
import { Injectable, NestMiddleware } from '@nestjs/common';
import type { Request, Response } from 'express';
import { RequestContextService } from '@pas7/nestjs-request-context';
import { REQUEST_ID, USER_ID, TENANT_ID } from './ctx.keys';

@Injectable()
export class RequestContextMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: () => void) {
    const requestId = String(req.headers['x-request-id'] ?? crypto.randomUUID());
    const userId = req.headers['x-user-id'] ? String(req.headers['x-user-id']) : undefined;
    const tenantId = req.headers['x-tenant-id'] ? String(req.headers['x-tenant-id']) : undefined;

    res.setHeader('x-request-id', requestId);

    RequestContextService.run(() => {
      RequestContextService.set(REQUEST_ID, requestId);
      RequestContextService.set(USER_ID, userId);
      RequestContextService.set(TENANT_ID, tenantId);
      next();
    });
  }
}

3) Leggi il contesto nei servizi (niente param threading)

TS
import { Injectable } from '@nestjs/common';
import { RequestContextService } from '@pas7/nestjs-request-context';
import { REQUEST_ID, USER_ID } from './ctx.keys';

@Injectable()
export class BillingService {
  charge() {
    const requestId = RequestContextService.get(REQUEST_ID);
    const userId = RequestContextService.get(USER_ID);

    return { requestId, userId };
  }
}

Il vantaggio core: i tuoi servizi restano singleton e puliti, ma accedono comunque a contesto per-request. [10]

Code & microservizi: il confine dove molte implementazioni si rompono

ALS non attraversa magicamente i confini di processo. Se pubblichi un job in coda o chiami un altro servizio, devi propagare esplicitamente il contesto (come requestId / trace context). [6][7]

Un buon default è propagare:

- x-request-id (il tuo correlation ID)

- traceparent (W3C Trace Context) se fai distributed tracing. [6][7]

HTTP outbound example (pseudo-pattern)

TS
const headers = {
  'x-request-id': RequestContextService.get(REQUEST_ID),
  'traceparent': currentTraceparent,
};

Queue job example (pseudo-pattern)

TS
await queue.add('jobName', {
  data: payload,
  ctx: {
    requestId: RequestContextService.get(REQUEST_ID),
    tenantId: RequestContextService.get(TENANT_ID),
  },
});

Nel consumer del job, inizializza un nuovo contesto ALS e ripristina i campi propagati prima di eseguire la business logic.

Se scegli consumer request-scoped per i job, Nest nota che creano una nuova istanza per job — trade-off simili allo scope per request HTTP. [13]

Testing: come evitare leak di contesto silenziosi in produzione

I bug di contesto sono famosi perché sembrano ok in locale ma falliscono sotto concorrenza.

La strategia minima di test dovrebbe includere:

- Test paralleli: due request simultanee non devono vedere il contesto l’una dell’altra.

- Test “async boundary”: task ritardati (setTimeout, handler messaggi) devono mantenere il contesto (o intenzionalmente non mantenerlo, se lo progetti così). [3]

- Test di propagazione coda: publish → consume ripristina contesto esplicitamente. [6][7]

La libreria PAS7 include una storia di testing in-repo (e si posiziona con un approccio testkit); se vai DIY, devi costruire guardrail equivalenti. [10]

Cosa scegliere (una regola semplice)

Se vuoi una decisione rapida senza rileggere tutto:

  • Scegli DIY ALS se vuoi dipendenze minime e sei pronto a gestire test e casi limite in autonomia. Parti dalla ricetta Nest. [2]

  • Scegli nestjs-cls se ti serve un ecosistema maturo (transazioni, proxy providers, use case più ampi). [8]

  • Scegli @pas7/nestjs-request-context se vuoi un layer snello, type-safe, NestJS-first con adapter ed ergonomia pulita. [10]

  • Evita REQUEST-scoped DI come default — usalo solo quando serve davvero instanziazione per-request e puoi controllare il blast radius. Nest avverte su performance e cascading scope. [1]

Se stai costruendo un prodotto NestJS serio

Il request context è una di quelle decisioni “piccole” che determinano se la codebase resta pulita a 30 endpoint o collassa a 300.

Se stai costruendo un prodotto NestJS e vuoi aiuto con architettura backend, osservabilità o automazione — PAS7 Studio può aiutarti a progettare e implementare sistemi di livello produzione.

Leggi di più: https://pas7.com.ua/blog

Fonti e riferimenti incrociati

Tutti i link sotto sono direttamente rilevanti per il tema e sono stati usati per supportare affermazioni e confronti sopra.

FAQ

Il REQUEST scope in NestJS è sempre una cattiva idea?

No — ma è rischioso come default. Nest avverte che i provider request-scoped impattano performance e possono propagare lo scope nelle dipendenze. Usalo solo quando serve davvero instanziazione per-request. [1]

AsyncLocalStorage è “supportato ufficialmente” in NestJS?

NestJS fornisce una ricetta ufficiale e spiega come ALS possa essere un’alternativa ai provider REQUEST-scoped, ma non offre un’astrazione built-in. [2]

Il contesto ALS attraversa automaticamente microservizi o code?

No. ALS è solo in-process. Tra servizi devi propagare esplicitamente (header/metadata). OpenTelemetry usa W3C Trace Context (`traceparent`) per il tracing. [6][7]

Cosa può causare perdita di contesto in ALS?

Node nota che la perdita di contesto può accadere in rare situazioni, specialmente con API a callback o thenable custom; le soluzioni includono promisify o AsyncResource per bindare correttamente il contesto. [3]

`@pas7/nestjs-request-context` è rilevante e competitivo per questo tema?

Sì — mira esattamente a questo pain: request context tipizzato su ALS con ergonomia NestJS-first e adapter. È un’ottima scelta quando vuoi un layer snello e type-safe senza spingere l’app in REQUEST scope. [10]

Devo preoccuparmi degli update di sicurezza Node.js se uso ALS?

Sì, tieni Node aggiornato. A gennaio 2026 Node ha rilasciato una mitigazione legata alla dipendenza dell’ecosistema da async_hooks/ALS, e vendor OTel/APM hanno pubblicato guidance di upgrade. [4][5][14]

Vuoi altri deep dive ingegneristici, basati su fonti?

Pubbliciamo articoli pratici e citabili su web engineering, automazione, sicurezza e sviluppo prodotto — focalizzati su decisioni che contano davvero in produzione.

Articoli correlati

growthFebruary 15, 2026

AI SEO / GEO nel 2026: i tuoi prossimi clienti non sono umani — sono agenti

La ricerca sta passando dai click alle risposte. Bot e agenti AI scansionano, citano, raccomandano e sempre più spesso acquistano. Scopri cosa significa AI SEO / GEO, perché la SEO classica non basta più e come PAS7 Studio aiuta i brand a vincere visibilità nel web “agentico”.

Leggere →
telegram-media-saverJanuary 8, 2025

Tag automatici e ricerca per link salvati

Integra con GDrive/S3/Notion per tag automatici e ricerca veloce tramite API di ricerca

Leggere →
servicesJanuary 1, 2025

Sviluppo di bot e servizi di automazione

Sviluppo professionale di bot Telegram e automazione dei processi aziendali: chatbot, assistenti AI, integrazioni CRM, automazione dei flussi di lavoro.

Leggere →
backend-engineeringFebruary 15, 2026

Bun vs Node.js nel 2026: perché Bun sembra più veloce (e come valutare l’app prima di migrare)

Bun è un toolkit JavaScript all-in-one più rapido: runtime, package manager, bundler e test runner. Qui trovi cosa è reale (con benchmark), cosa può rompersi e come ottenere un audit di readiness gratuito con @pas7-studio/bun-ready.

Leggere →

Web Development for Your Business

Professional development of modern web applications and websites

Servizi di sviluppo web

Servizi professionali di sviluppo web per il business: dalle landing page a piattaforme web complesse con design responsive e ottimizzazione SEO.

Scopri di più →

Sviluppo professionale per la tua attività

Creiamo soluzioni web moderne e bot per le aziende. Scopri come possiamo aiutarti a raggiungere i tuoi obiettivi.