PAS7 Studio

Tehnologija

NestJS problem Request Contexta: Request-scoped DI vs AsyncLocalStorage (ALS) — praktični vodič za produkciju (2026)

Dubinska, izvorima potkrijepljena analiza jedne od najbolnijih stvari u NestJS-u: request context (user, tenant, correlation ID, tracing) bez pretvaranja DI grafa u REQUEST scope. Uključuje usporedbe, realne pattern-e i praktični vodič s @pas7/nestjs-request-context.

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

Što dobivaš iz ovog članka

Ovo nije “teorijski post”. Ovo je praktični vodič koji možeš primijeniti u stvarnom NestJS codebaseu — s provjerenim izvorima i jasnim okvirom za odluku.

  • Što “request context” zapravo znači u NestJS-u (i zašto boli). [1][2][3]

  • Zašto REQUEST-scoped provideri izgledaju lako — ali često postanu performance i arhitekturna zamka. [1]

  • Kako AsyncLocalStorage (ALS) rješava core pain (i gdje još može puknuti). [2][3]

  • Kako to rade kompanije: correlation ID-jevi, tracing, OpenTelemetry propagacija, sigurne granice konteksta. [4][5][6][7]

  • Kurirana usporedba relevantnih paketa (prednosti/nedostaci i za koje potrebe su najbolji). [8][9][10][11][12]

  • Vodič za produkciju + code patterni koje možeš kopirati (HTTP + queue + microservices). [2][6][7]

  • Gdje se uklapa @pas7/nestjs-request-context i kada je konkurentan izbor. [10]

Najbolniji NestJS problem: request context bez kolateralne štete

“Request context” je sve što želiš čitati duboko u servisima bez provlačenja kroz svaku metodu: current user, tenant, permissions, request ID, trace ID-jevi, transaction handle, locale, feature flags i još.

U NestJS-u obično završiš u jednom od ova tri scenarija:

- Prosljeđuješ kontekst eksplicitno kroz parametre (pouzdano, ali bučno i teško za održavanje).

- Koristiš REQUEST-scoped providere (jednostavan API, ali može pretvoriti velik dio appa u per-request instanciranje). [1]

- Koristiš ALS-kontekst (čisti pozivi, provideri ostaju singleton, ali treba ispravan setup i svijest o rubnim slučajevima). [2][3]

Zašto REQUEST-scoped DI postaje zamka (i zašto timovi kasnije žale)

NestJS to jasno kaže: request-scoped provideri dodaju dodatno opterećenje jer se instance kreiraju po requestu i — još važnije — scope se “širi” kroz ovisnosti. [1]

Dvije citate koje trebaš imati na umu kad dizajniraš arhitekturu:

> “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]

Kako realne aplikacije upadnu u problem: jedan request-scoped “datasource / logger / context” postane korijenska ovisnost i odjednom se controlleri, servisi i repozitoriji rekreiraju po requestu. Nest posebno spominje multi-tenant aplikacije kao čest primjer. [1]

Da, Nest kaže da utjecaj može biti “~5% latency-wise” u dobro dizajniranoj aplikaciji — ali pravi trošak je često arhitekturni: teže je rezonirati o lifetimeu, caching-u i “obliku” DI stabla. [1]

AsyncLocalStorage u jednoj minuti: zašto savršeno mapira request context

Node.js AsyncLocalStorage je praktički “thread-local storage za async kod”: veže state uz execution chain (promise/callback) i omogućuje ti da ga kasnije čitaš bez prosljeđivanja parametara. [3]

Node docs preporučuju AsyncLocalStorage umjesto DIY implementacije na async_hooks, opisujući ga kao performant i memory-safe. [3]

Ali nije magija. Gubitak konteksta može se dogoditi u “rijetkim situacijama”, posebno oko callback-based API-ja ili custom thenables — Node preporučuje promisify ili AsyncResource za pravilno bindanje execution contexta. [3]

Pitanje je: možemo li pouzdano “omotati” Nest request lifecycle tako da sve downstream vidi isti store? NestJS kaže: da — kroz middleware / entry point lifecyclea. [2]

NestJS službeni smjer: ALS kao alternativa REQUEST scopeu

NestJS eksplicitno pozicionira ALS kao način propagacije statea bez parametara i kao alternativu REQUEST-scoped providerima “i nekim njihovim ograničenjima”. [2]

Core ideja: omotaj request rano (middleware) s als.run(store, () => next()). Onda bilo koji provider kasnije može čitati iz ALS storea.

Minimalni NestJS-style primjer (pojednostavljen iz službenog recepta): [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');
  }
}

Ovo je “clean core” pattern. Production setupovi dodaju: sigurno parsiranje headera, echo requestId u response, trace korelaciju, queue propagaciju i testiranje.

Kako to rade kompanije: correlation ID + tracing + sigurna propagacija

U produkciji request context nije samo “current user”. Najčešći driveri su observability i incident response: trebaš logove, traceove i metrike koje se pouzdano koreliraju kroz servise.

To je točno ono što OpenTelemetry context propagation radi: prenosi trace/span context kroz procesne i mrežne granice (default W3C Trace Context headeri poput traceparent). [6][7]

Dva praktična takeawaya iz enterprise svijeta:

- In-process kontekst može biti u ALS-u, ali preko service boundaryja moraš ga propagirati eksplicitno (HTTP headeri, message metadata itd.). [6][7]

- Ne stavljaj osjetljive podatke u cross-service propagaciju. OpenTelemetry eksplicitno upozorava protiv secrets/PII u baggage-like propagiranim key-valueovima. [6]

Operativna napomena za 2026 (nemoj ignorirati ako se oslanjaš na ALS kroz APM/tracing): Node.js je u siječnju 2026 izbacio mitigaciju za async_hooks/ALS-related DoS edge case i preporučuje patchane verzije. APM i OTel timovi su objavili guidance. [4][5]

Paketi (2026): što postoji, što je solidno, što je rizično

Ispod je sažeta usporedba paketa koje timovi stvarno koriste za NestJS request context. Cilj nije “tko ima više zvjezdica”, nego: korektnost, ergonomija, integracije i koliko dobro izbjegava REQUEST scope.

Brza tablica usporedbe

PackageCore approachBest forKey trade-offs
nestjs-clsALS + ClsService + Proxy Providers + pluginsfull-featured context + transakcijeviše apstrakcije; treba naučiti API surface
@pas7/nestjs-request-contextALS + typed keys + decorators + adaptersstrict, lightweight, typed request contextnoviji ekosustav; ovisi o integracijama koje trebaš
@medibloc/nestjs-request-contextALS-based request contextjednostavan ALS contextuži scope vs nestjs-cls
nestjs-pino (context dio)logging integracija preko ALSkontekstualni logging s Pinofokus na logging (nije generalni context framework)
DIY (Nest recept)raw ALSminimalno + full controlti pokrivaš edge caseove + testove

Detalji sa izvorima:

- nestjs-cls se pozicionira kao continuation-local storage modul za NestJS baziran na AsyncLocalStorage, navodi use-caseove poput request ID trackinga, multi-tenancyja i propagacije transakcija bez parametara. [8]

- nestjs-pino dokumentira ključan argument: izbjegavanje REQUEST-scoped providera zbog performance dropa, te korištenje ALS-a za request-bound loggere. [11]

- Nest službeni recept priznaje ALS kao alternativu REQUEST scopeu — ali i kaže da NestJS ne isporučuje built-in apstrakciju, pa ili implementiraš ili koristiš library. [2]

Deep dive: kada je `nestjs-cls` najbolji izbor

Ako su ti potrebe široke (multi-tenancy + transakcije + proxy provideri + “request context gdje REQUEST scope nije podržan”), nestjs-cls je često najkompletniji toolbox. Docs naglašavaju široke use-caseove i izbjegavanje nezgrapnih REQUEST-scoped pristupa. [8]

Čest razlog: transakcije koje se propagiraju bez prosljeđivanja transaction objekta kroz sve slojeve, plus ekosustav pluginova. [8]

Ako si već duboko u tom ekosustavu, prelazak kasnije često nema smisla — ali ako ti trebaju samo 2–3 polja (requestId, userId, tenantId), možda želiš nešto manje.

Gdje se uklapa `@pas7/nestjs-request-context` (i kada je konkurentan)

@pas7/nestjs-request-context je direktno usklađen s ovim problemom: request context preko AsyncLocalStorage uz singleton DI, s jakim fokusom na tipnu sigurnost (typed keys) i čistu NestJS ergonomiju. [10]

Zašto je relevantan za ovaj članak:

- Typed ContextKey<T> za vrijednosti konteksta (manje stringly-typed “magic keys”). [10]

- NestJS ergonomija: dekoratori (npr. parameter decorators) da čitaš context bez plumbing-a. [10]

- HTTP adapteri za Express i Fastify u NestJS okruženjima. [10]

- Eksplicitno pozicioniranje protiv REQUEST-scope pristupa zbog performance/architecture razloga. [10]

Caveat (pošteno): repo kaže da je Fastify adapter izvan NestJS-a limitiran zbog Fastify + AsyncLocalStorage incompatibilities, pa ga tretiraj kao NestJS-first. [10]

Praktični setup: production-friendly vodič (gotovi patterni)

Ovo je “do it right” checklist: gdje initati context, što spremati, kako propagirati prema queue/microservices i kako testirati da ne shipaš context leakove.

Preporučena polja konteksta (praktični default)

- requestId: stabilan correlation ID; vrati ga kao x-request-id u response.

- userId: interni user identifikator (izbjegni email/telefon).

- tenantId: ako si multi-tenant.

- traceId / spanId: ako imaš tracing (ili izvedi iz OTel contexta).

- authLevel / role: ako treba za auth odluke (u kritičnim flowovima preferiraj eksplicitne provjere).

Pattern A: Minimalni DIY ALS (dobro ako želiš full control)

Koristi Nest recept middleware pristup i implementiraj mali wrapper (s testovima). [2]

Pattern B: nestjs-cls kad trebaš ekosustav

Ako trebaš transaction propagation pluginove i proxy provider pattern, nestjs-cls je jak izbor. [8]

Pattern C: @pas7/nestjs-request-context kad želiš strict typed keys + lean surface

Ako ti treba čisti, tipizirani request context (requestId/userId/tenantId + još malo), i cijeniš NestJS-first adapter layer, PAS7 library je smislen izbor. [10]

Initialization point

Rani lifecycle

Inicijaliziraj context što ranije (middleware je najsigurniji za HTTP u Nestu). Nest recept koristi middleware baš zbog toga. [2]

Zadrži DI singleton

Izbjegni REQUEST scope

REQUEST-scoped provideri mogu “zaraziti” scope kroz dependencies i dodati opterećenje po requestu. Nest eksplicitno upozorava. [1]

Cross-service propagation

Eksplicitno

ALS radi samo in-process. Preko servisa, propagiraj headerima/metadata. OTel defaulta na W3C Trace Context (traceparent). [6][7]

Security

Bez tajni u contextu

Ne propagiraj osjetljive podatke kroz context/baggage. OTel eksplicitno upozorava protiv secrets/PII u baggage-like poljima. [6]

Dijagram: request -> middleware -> ALS store -> services -> logger -> db -> queue propagation

Siguran tok request-contexta: inicijaliziraj rano, čitaj bilo gdje, propagiraj eksplicitno preko granica

Section pas7-quickstart screenshot

Code patterni: `@pas7/nestjs-request-context` (typed keys + ergonomija)

Ispod su ilustrativni patterni bazirani na pristupu libraryja (typed ContextKey<T>, Nest-first ergonomija, adapteri). Provjeri točna API imena u repou prije production lock-ina. [10]

1) Definiraj typed keys (jedan modul/shared package)

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) Init u middlewareu (HTTP entry point)

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) Čitaj context u servisima (bez param threading-a)

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 };
  }
}

Core win: servisi ostaju singleton i čisti, ali i dalje imaju per-request kontekst. [10]

Queue & microservices: granica gdje mnoge implementacije pucaju

ALS ne prelazi procesne granice. Ako šalješ job u queue ili zoveš drugi servis, moraš eksplicitno propagirati context (requestId/trace). [6][7]

Dobar default za propagaciju:

- x-request-id (tvoj correlation ID)

- traceparent (W3C Trace Context) ako imaš 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),
  },
});

Kod consumera, inicijaliziraj novi ALS context i restoreaj propagirana polja prije business logike.

Ako koristiš request-scoped consumere za jobove, Nest kaže da se instanca kreira po jobu — slični trade-offi kao HTTP request scope. [13]

Testiranje: kako izbjeći tihi context leak u produkciji

Context bugovi su zloglasni jer lokalno izgledaju ok, a pod concurrencyjem puknu.

Minimum test strategija treba uključiti:

- Paralelni request testovi: dvije simultane requeste ne smiju vidjeti tuđi context.

- “Async boundary” testovi: odgođeni taskovi (setTimeout, message handleri) moraju zadržati context (ili ga namjerno ne zadržati, ako tako dizajniraš). [3]

- Queue propagation testovi: publish → consume eksplicitno restorea context. [6][7]

PAS7 library ima testing story u repou (i testkit approach); ako ideš DIY, trebaš ekvivalentne guardraile. [10]

Što odabrati (jednostavno pravilo)

Ako želiš brzu odluku bez ponovnog čitanja svega:

  • Odaberi DIY ALS ako želiš minimalne ovisnosti i spreman si pokriti testove i rubne slučajeve. Kreni od Nest recepta. [2]

  • Odaberi nestjs-cls ako trebaš zreli ekosustav (transakcije, proxy provideri, širi use-caseovi). [8]

  • Odaberi @pas7/nestjs-request-context ako želiš lean, type-safe, NestJS-first context layer s adapterima i čistom ergonomijom. [10]

  • Izbjegavaj REQUEST-scoped DI kao default — koristi ga samo kad stvarno treba per-request instanciranje i možeš kontrolirati blast radius. Nest upozorava na performance i cascading scope. [1]

Ako gradiš ozbiljan NestJS proizvod

Request context je jedna od onih “malih” odluka koja odlučuje hoće li codebase ostati čist na 30 endpointa ili se raspasti na 300.

Ako gradiš NestJS proizvod i želiš pomoć oko backend arhitekture, observabilityja ili automatizacije — PAS7 Studio može pomoći dizajnirati i implementirati production-grade sustave.

Pročitaj više: https://pas7.com.ua/blog

Izvori i unakrsne reference

Svi linkovi ispod su direktno relevantni i korišteni za factual claimove i usporedbe iznad.

FAQ

Je li REQUEST scope u NestJS-u uvijek loš?

Ne — ali je rizičan kao default. Nest upozorava da request-scoped provideri utječu na performance i mogu proširiti scope kroz dependencies. Koristi ga samo kad stvarno treba per-request instanciranje. [1]

Je li AsyncLocalStorage “službeno podržan” u NestJS-u?

NestJS ima službeni recept i objašnjava kako ALS može biti alternativa REQUEST-scoped providerima, ali ne isporučuje built-in apstrakciju. [2]

Može li ALS context magično prijeći microservice ili queue granice?

Ne. ALS je samo in-process. Preko granica moraš propagirati eksplicitno (headeri/metadata). OpenTelemetry defaulta na W3C Trace Context (`traceparent`). [6][7]

Što uzrokuje gubitak ALS konteksta?

Node navodi da se gubitak konteksta može dogoditi u rijetkim situacijama, posebno oko callback API-ja ili custom thenables; preporuke su promisify ili AsyncResource. [3]

Je li `@pas7/nestjs-request-context` relevantan i konkurentan za ovu temu?

Da — cilja baš ovaj pain: tipizirani request context preko ALS-a s NestJS-first ergonomijom i adapterima. Dobar je fit kad želiš lean, type-safe layer bez guranja appa u REQUEST scope. [10]

Moram li paziti na Node.js security updateove ako koristim ALS?

Da. Drži Node patchanim. U siječnju 2026 Node je izdao mitigaciju vezanu uz async_hooks/ALS ekosustav, a OTel/APM vendor-i su dali upgrade guidance. [4][5][14]

Želiš još dubinskih, izvorima potkrijepljenih engineering analiza?

Objavljujemo praktične, citabilne članke o web engineeringu, automatizaciji, sigurnosti i product developmentu — fokusirane na odluke koje stvarno znače u produkciji.

Povezani članci

growthFebruary 15, 2026

AI SEO / GEO u 2026: vaši sljedeći kupci nisu ljudi — nego agenti

Pretraživanje se pomiče s klikova na odgovore. Botovi i AI agenti pretražuju, citiraju, preporučuju i sve češće kupuju. Saznajte što znači AI SEO / GEO, zašto klasični SEO više nije dovoljan i kako PAS7 Studio pomaže brendovima pobijediti u agentičkom webu.

Čitati →
telegram-media-saverJanuary 8, 2025

Automatsko označavanje i pretraga spremljenih linkova

Integracija s GDrive/S3/Notion za automatsko označavanje i brzu pretragu putem search API-ja

Čitati →
servicesJanuary 1, 2025

Razvoj botova i usluge automatizacije

Profesionalni razvoj Telegram botova i automatizacija poslovnih procesa: chatbotovi, AI asistenti, CRM integracije, automatizacija radnih tijekova.

Čitati →
backend-engineeringFebruary 15, 2026

Bun vs Node.js u 2026: zašto Bun djeluje brže (i kako provjeriti aplikaciju prije migracije)

Bun je brži all-in-one JavaScript toolkit: runtime, package manager, bundler i test runner. Donosimo što je stvarno (uz benchmarke), što se može pokvariti i kako dobiti besplatni readiness audit pomoću @pas7-studio/bun-ready.

Čitati →

Web Development for Your Business

Professional development of modern web applications and websites

Usluge web razvoja

Profesionalne usluge web razvoja za poslovanje: od landing stranica do složenih web platformi s responzivnim dizajnom i SEO optimizacijom.

Saznaj više →

Profesionalni razvoj za vaše poslovanje

Kreiramo moderne web rješenja i botove za poduzeća. Saznajte kako vam možemo pomoći u postizanju ciljeva.