[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"search-suggestions":44,"article-nestjs-weekly-module-encapsulation-exports":91,"related-nestjs-weekly-module-encapsulation-exports":522,"code:plain:true:17d0d1s":552,"code:ts:true:u1give":553,"code:ts:true:hsjei2":554,"code:ts:true:nrk99j":555,"code:ts:true:1bc40ow":556,"code:ts:true:otjiwa":557,"code:ts:true:d52fwq":558,"code:ts:true:xuofs3":559,"code:ts:true:1bw78qf":560,"code:ts:true:4kp6a0":561,"code:ts:true:1yo9rn8":562,"code:ts:true:1168c3p":563,"code:ts:true:1sqm3ql":564,"code:ts:true:101isdo":565,"comments-01a0821b-4733-762d-bf96-b68c7eb140c0":566},[4,20,32],{"id":5,"slug":6,"name":7,"tagline":8,"description":9,"accentFrom":10,"accentTo":11,"icon":12,"defaultLocale":13,"locales":14,"features":16,"position":19},"019fe637-3d33-714b-b57f-23e163ffca0c","dev","Web Development","Read it. Run it. Prove it.","A post a day on modern web development — most with an editable playground and a quiz that explains every answer. Free, no account needed.","violet-500","cyan-400","◇","en",[13,15],"fa",{"courses":17,"paths":17,"articles":17,"exams":18,"flashcards":18,"packages":17,"community":17,"certificates":17,"teams":17,"commerce":17},true,false,0,{"id":21,"slug":22,"name":23,"tagline":24,"description":25,"accentFrom":26,"accentTo":10,"icon":27,"defaultLocale":13,"locales":28,"features":30,"position":31},"019fe637-3dc2-754c-8657-0f175bfee7c6","lang","Languages","Learn a language the way you learn a codebase.","Grammar explained the way good documentation explains an API — one idea at a time, each with a quiz.","amber-400","⌘",[13,15,29],"es",{"courses":18,"paths":18,"articles":17,"exams":18,"flashcards":17,"packages":18,"community":17,"certificates":17,"teams":18,"commerce":18},2,{"id":33,"slug":34,"name":35,"tagline":36,"description":37,"accentFrom":38,"accentTo":39,"icon":40,"defaultLocale":13,"locales":41,"features":42,"position":43},"7b3c16f2-931d-410e-802e-e1fa4edab7de","soft","Soft Skills","The half of the job nobody wrote documentation for.","Weekly, on the parts of working life that decide more than your code does — first weeks, meetings, interviews, promotions, and the people around you. Written from what actually happens, and recorded as a podcast you can listen to on the walk.","emerald-400","teal-300","◉",[13],{"courses":18,"paths":18,"articles":17,"exams":18,"flashcards":18,"packages":18,"community":17,"certificates":18,"teams":18,"commerce":18},3,[45,49,53,57,61,65,69,72,76,80,83,87],{"slug":46,"name":47,"articles":48},"webdev","Webdev",89,{"slug":50,"name":51,"articles":52},"javascript","Javascript",73,{"slug":54,"name":55,"articles":56},"frontend","Frontend",69,{"slug":58,"name":59,"articles":60},"css","Css",31,{"slug":62,"name":63,"articles":64},"tutorial","Tutorial",20,{"slug":66,"name":67,"articles":68},"typescript","Typescript",12,{"slug":70,"name":71,"articles":68},"performance","Performance",{"slug":73,"name":74,"articles":75},"react","React",10,{"slug":77,"name":78,"articles":79},"browser","Browser",7,{"slug":81,"name":82,"articles":79},"node","Node",{"slug":84,"name":85,"articles":86},"grammar","Grammar",6,{"slug":88,"name":89,"articles":90},"html","Html",5,{"id":92,"slug":93,"title":94,"subtitle":95,"excerpt":96,"coverUrl":97,"locale":13,"readingMinutes":98,"publishedAt":99,"viewCount":100,"likeCount":19,"commentCount":19,"author":101,"vertical":106,"topic":107,"tags":110,"_count":115,"playground":117,"body":119,"bodyMd":497,"seo":498,"translationGroupId":500,"series":501,"podcastUrl":95,"verticalId":5,"thread":510,"assessments":512,"translations":518,"quiz":520},"01a0821b-4733-762d-bf96-b68c7eb140c0","nestjs-weekly-module-encapsulation-exports","NestJS Module Encapsulation Explained (with Cheat Sheet)",null,"How NestJS module boundaries actually work: what exports really cross, why @Global() isn't a shortcut, and how forwardRef breaks circular module dependencies.","\u002Fmedia\u002Fcovers\u002Fnestjs-weekly-module-encapsulation-exports.png",14,"2026-09-11T10:56:27.927Z",29,{"id":102,"name":103,"username":104,"avatarUrl":95,"headline":105},"019fe637-3c25-7088-9034-39c9f15dc3c8","Parsa Jiravand","parsa","Frontend engineer · building bestpractic",{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":108,"name":109},"nestjs","Nestjs",[111,112,113,114],{"slug":108,"name":109,"color":95},{"slug":81,"name":82,"color":95},{"slug":66,"name":67,"color":95},{"slug":62,"name":63,"color":95},{"assessments":116},1,{"slug":93,"title":118},"NestJS module graph — interactive playground",{"blocks":120,"version":116},[121,125,131,134,139,142,151,154,157,160,163,166,181,184,187,192,196,200,204,207,210,213,216,219,223,226,229,232,235,238,241,244,247,251,254,257,260,264,267,270,273,277,280,283,287,290,294,297,300,303,306,310,313,316,319,323,327,330,333,337,340,343,346,354,357,366,369,372,375,378,381,384,388,391,394,397,401,404,408,411,415,418,421,465,468,476,479,482,485,488,491],{"id":122,"html":123,"type":124},"b1","\u003Cp>A NestJS app boots cleanly for weeks. Then a teammate adds \u003Ccode>NotificationsModule\u003C\u002Fcode>, wires \u003Ccode>NotificationsService\u003C\u002Fcode> into \u003Ccode>OrdersService\u003C\u002Fcode>&#39;s constructor, runs the app — and Nest refuses to start:\u003C\u002Fp>","paragraph",{"id":126,"code":127,"type":128,"language":129,"highlight":130},"b2","Nest can't resolve dependencies of the OrdersService (?). Please make sure that the argument NotificationsService at index [1] is available in the OrdersModule context.\n\nPotential solutions:\n- Is OrdersModule a valid NestJS module?\n- If NotificationsService is exported from a separate @Module, is that module imported within OrdersModule?","code","plain",[],{"id":132,"html":133,"type":124},"b3","\u003Cp>Nothing about \u003Ccode>NotificationsService\u003C\u002Fcode> itself is wrong — it&#39;s decorated with \u003Ccode>@Injectable()\u003C\u002Fcode>, it compiles, its own tests pass in isolation. The teammate even double-checked it&#39;s listed in \u003Ccode>NotificationsModule\u003C\u002Fcode>&#39;s \u003Ccode>providers\u003C\u002Fcode> array. It is. That&#39;s not the part that&#39;s missing.\u003C\u002Fp>",{"id":135,"html":136,"text":137,"type":138,"level":31},"b4","What you&#39;ll learn","What you'll learn","heading",{"id":140,"html":141,"type":124},"b5","\u003Cp>By the end of this article you&#39;ll be able to:\u003C\u002Fp>",{"id":143,"type":144,"items":145,"ordered":18},"b6","list",[146,147,148,149,150],"Explain what a NestJS module boundary actually is, and why &quot;it&#39;s in \u003Ccode>providers\u003C\u002Fcode>&quot; isn&#39;t the same question as &quot;can this other module see it&quot;","Fix the exact error above by understanding what \u003Ccode>exports\u003C\u002Fcode> really crosses","Decide when \u003Ccode>@Global()\u003C\u002Fcode> is the right tool, and why it&#39;s the exception, not the default","Recognize a module-level circular dependency and choose between \u003Ccode>forwardRef()\u003C\u002Fcode> and the better fix: restructuring","Read a dynamic module (\u003Ccode>forRoot\u003C\u002Fcode>\u002F\u003Ccode>forFeature\u003C\u002Fcode>) as the same encapsulation rules, just built at runtime",{"id":152,"html":153,"text":153,"type":138,"level":31},"b7","Who this is for",{"id":155,"html":156,"type":124},"b8","\u003Cp>You&#39;ve built at least one multi-module NestJS app — a couple of feature modules, each with its own controller and service. You don&#39;t need to have hit the error above yet; we&#39;ll build it from nothing and then fix it properly.\u003C\u002Fp>",{"id":158,"html":159,"type":124},"b9","\u003Cp>This article is written against \u003Cstrong>NestJS 12.x\u003C\u002Fstrong> (verified against the \u003Ccode>nestjs\u002Fnest\u003C\u002Fcode> GitHub release history — \u003Ccode>v12.0.0\u003C\u002Fcode> shipped August 27, 2026). Module registration, \u003Ccode>exports\u003C\u002Fcode>, \u003Ccode>@Global()\u003C\u002Fcode>, and \u003Ccode>forwardRef()\u003C\u002Fcode> are core-container behavior, unchanged in shape across the 10.x → 12.x line.\u003C\u002Fp>",{"id":161,"html":162,"type":124},"b10","\u003Cp>If you haven&#39;t read it yet, the previous episode covers \u003Ca href=\"https:\u002F\u002Fdev.to\u002Fparsajiravand\u002Fnestjs-dependency-injection-explained-with-cheat-sheet\">how the DI container resolves providers and what &quot;singleton&quot; really means\u003C\u002Fa> — this article assumes that mental model and builds the module-level picture on top of it, but you don&#39;t need it to follow along here.\u003C\u002Fp>",{"id":164,"html":165,"text":165,"type":138,"level":31},"b11","Table of contents",{"id":167,"type":144,"items":168,"ordered":18},"b12",[169,170,171,172,173,174,175,176,177,178,179,180],"\u003Ca href=\"#the-problem-exported-everywhere-visible-nowhere\">The problem: exported everywhere, visible nowhere\u003C\u002Fa>","\u003Ca href=\"#the-mental-model-a-module-is-a-boundary-not-a-folder\">The mental model: a module is a boundary, not a folder\u003C\u002Fa>","\u003Ca href=\"#stage-1-the-smallest-module-boundary\">Stage 1: the smallest module boundary\u003C\u002Fa>","\u003Ca href=\"#stage-2-exports-what-actually-crosses-the-boundary\">Stage 2: exports — what actually crosses the boundary\u003C\u002Fa>","\u003Ca href=\"#stage-3-re-exporting-passing-a-module-through\">Stage 3: re-exporting — passing a module through\u003C\u002Fa>","\u003Ca href=\"#stage-4-global-removing-the-boundary-on-purpose\">Stage 4: \u003Ccode>@Global()\u003C\u002Fcode> — removing the boundary on purpose\u003C\u002Fa>","\u003Ca href=\"#stage-5-dynamic-modules-follow-the-same-rules\">Stage 5: dynamic modules follow the same rules\u003C\u002Fa>","\u003Ca href=\"#stage-6-circular-dependencies-between-modules\">Stage 6: circular dependencies between modules\u003C\u002Fa>","\u003Ca href=\"#edge-cases-and-gotchas\">Edge cases and gotchas\u003C\u002Fa>","\u003Ca href=\"#best-practices\">Best practices\u003C\u002Fa>","\u003Ca href=\"#faq\">FAQ\u003C\u002Fa>","\u003Ca href=\"#cheat-sheet\">Cheat sheet\u003C\u002Fa>",{"id":182,"html":183,"text":183,"type":138,"level":31},"b13","The problem: exported everywhere, visible nowhere",{"id":185,"html":186,"type":124},"b14","\u003Cp>Here&#39;s the setup, trimmed to the part that matters:\u003C\u002Fp>",{"id":188,"code":189,"type":128,"language":190,"highlight":191},"b15","\u002F\u002F notifications.service.ts\n@Injectable()\nexport class NotificationsService {\n  send(userId: string, message: string) {\n    \u002F\u002F ...\n  }\n}","ts",[],{"id":193,"code":194,"type":128,"language":190,"highlight":195},"b16","\u002F\u002F notifications.module.ts\n@Module({\n  providers: [NotificationsService],\n})\nexport class NotificationsModule {}",[],{"id":197,"code":198,"type":128,"language":190,"highlight":199},"b17","\u002F\u002F orders.module.ts\n@Module({\n  imports: [NotificationsModule],\n  controllers: [OrdersController],\n  providers: [OrdersService],\n})\nexport class OrdersModule {}",[],{"id":201,"code":202,"type":128,"language":190,"highlight":203},"b18","\u002F\u002F orders.service.ts\n@Injectable()\nexport class OrdersService {\n  constructor(\n    private readonly repo: OrdersRepository,\n    private readonly notifications: NotificationsService, \u002F\u002F ← this is what fails\n  ) {}\n}",[],{"id":205,"html":206,"type":124},"b19","\u003Cp>Everything here looks correct by the checklist most people carry around: \u003Ccode>@Injectable()\u003C\u002Fcode> on the service, listed in a module&#39;s \u003Ccode>providers\u003C\u002Fcode>, that module imported by the consumer. And yet Nest still can&#39;t resolve it — because the checklist is missing one line: \u003Ccode>NotificationsModule\u003C\u002Fcode> never says \u003Ccode>exports: [NotificationsService]\u003C\u002Fcode>.\u003C\u002Fp>",{"id":208,"html":209,"text":209,"type":138,"level":31},"b20","The mental model: a module is a boundary, not a folder",{"id":211,"html":212,"type":124},"b21","\u003Cp>\u003Cstrong>The mental model:\u003C\u002Fstrong> a NestJS module isn&#39;t an organizational folder — it&#39;s a real wall around a slice of the DI container. Each module gets its own injector, and that injector only knows two kinds of providers: the ones listed directly in its own \u003Ccode>providers\u003C\u002Fcode> array, and the ones explicitly handed to it through \u003Ccode>imports\u003C\u002Fcode> — and only the subset of \u003Cem>those\u003C\u002Fem> that the imported module put in its own \u003Ccode>exports\u003C\u002Fcode> array.\u003C\u002Fp>",{"id":214,"html":215,"type":124},"b22","\u003Cp>\u003Ccode>providers\u003C\u002Fcode> answers &quot;what can this module build?&quot; \u003Ccode>exports\u003C\u002Fcode> answers a completely different question: &quot;what am I willing to hand to whoever imports me?&quot; A provider can be fully registered and working \u003Cem>inside\u003C\u002Fem> its own module and still be completely invisible to every other module, because \u003Ccode>providers\u003C\u002Fcode> alone doesn&#39;t open the wall — only \u003Ccode>exports\u003C\u002Fcode> does.\u003C\u002Fp>",{"id":217,"html":218,"type":124},"b23","\u003Cp>That&#39;s exactly the gap in the bug above: \u003Ccode>NotificationsModule\u003C\u002Fcode> builds \u003Ccode>NotificationsService\u003C\u002Fcode> correctly for its own internal use, but never lists it in \u003Ccode>exports\u003C\u002Fcode>. \u003Ccode>OrdersModule\u003C\u002Fcode> imports \u003Ccode>NotificationsModule\u003C\u002Fcode> — establishing an edge in the module graph — but that edge carries nothing across it, because the sending side never put anything on the wire.\u003C\u002Fp>",{"id":220,"code":221,"type":128,"language":190,"highlight":222},"b24","\u002F\u002F notifications.module.ts — the fix\n@Module({\n  providers: [NotificationsService],\n  exports: [NotificationsService], \u002F\u002F now it can leave this module\n})\nexport class NotificationsModule {}",[],{"id":224,"html":225,"type":124},"b25","\u003Cp>\u003Cstrong>Key concept:\u003C\u002Fstrong> \u003Ccode>imports\u003C\u002Fcode> opens a door between two modules; \u003Ccode>exports\u003C\u002Fcode> decides what&#39;s allowed to walk through it. A provider needs both — registered somewhere, and exported from wherever it&#39;s registered — before another module&#39;s injector can see it, no matter how correctly it&#39;s decorated.\u003C\u002Fp>",{"id":227,"html":228,"type":124},"b26","\u003C!-- playground:start -->",{"id":230,"html":231,"text":231,"type":138,"level":31},"b27","🎮 Try it yourself",{"id":233,"html":234,"type":124},"b28","\u003Cp>\u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fnestjs-weekly-module-encapsulation-exports\u002Fplayground\">▶️ Open the interactive playground →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":236,"html":237,"type":124},"b29","\u003Cp>\u003Cem>Runs right in your browser — poke at it and watch the concept react live.\u003C\u002Fem>\u003C\u002Fp>",{"id":239,"html":240,"type":124},"b30","\u003C!-- playground:end -->",{"id":242,"html":243,"text":243,"type":138,"level":31},"b31","Stage 1: the smallest module boundary",{"id":245,"html":246,"type":124},"b32","\u003Cp>A module with nothing exported is still a perfectly valid, fully functional module — for its own controllers and services:\u003C\u002Fp>",{"id":248,"code":249,"type":128,"language":190,"highlight":250},"b33","@Module({\n  controllers: [OrdersController],\n  providers: [OrdersService, OrdersRepository],\n})\nexport class OrdersModule {}",[],{"id":252,"html":253,"type":124},"b34","\u003Cp>\u003Ccode>OrdersController\u003C\u002Fcode> and \u003Ccode>OrdersService\u003C\u002Fcode> can inject \u003Ccode>OrdersRepository\u003C\u002Fcode> freely — they&#39;re all in the same injector. Nothing here needs an export, because nothing here needs to leave the module. The boundary only becomes visible the moment something \u003Cem>outside\u003C\u002Fem> \u003Ccode>OrdersModule\u003C\u002Fcode> wants in.\u003C\u002Fp>",{"id":255,"html":256,"text":256,"type":138,"level":31},"b35","Stage 2: exports — what actually crosses the boundary",{"id":258,"html":259,"type":124},"b36","\u003Cp>\u003Ccode>exports\u003C\u002Fcode> takes a subset of what&#39;s in \u003Ccode>providers\u003C\u002Fcode> (or a whole imported module — see the next stage) and makes it resolvable by any module that lists this one in its own \u003Ccode>imports\u003C\u002Fcode>:\u003C\u002Fp>",{"id":261,"code":262,"type":128,"language":190,"highlight":263},"b37","@Module({\n  providers: [OrdersService, OrdersRepository],\n  exports: [OrdersService], \u002F\u002F OrdersRepository stays private\n})\nexport class OrdersModule {}",[],{"id":265,"html":266,"type":124},"b38","\u003Cp>Only \u003Ccode>OrdersService\u003C\u002Fcode> is importable from elsewhere. \u003Ccode>OrdersRepository\u003C\u002Fcode> is an implementation detail — other modules that import \u003Ccode>OrdersModule\u003C\u002Fcode> get access to the service&#39;s public surface, not the repository it happens to use internally. This is deliberate, and it&#39;s the same instinct as a private class member: export the smallest set that satisfies every real consumer.\u003C\u002Fp>",{"id":268,"html":269,"text":269,"type":138,"level":31},"b39","Stage 3: re-exporting — passing a module through",{"id":271,"html":272,"type":124},"b40","\u003Cp>A module can also export a module it imported, without re-listing its individual providers — this passes the whole thing through:\u003C\u002Fp>",{"id":274,"code":275,"type":128,"language":190,"highlight":276},"b41","\u002F\u002F shared.module.ts\n@Module({\n  imports: [CacheModule],\n  exports: [CacheModule], \u002F\u002F re-export: anyone importing SharedModule also gets CacheModule's exports\n})\nexport class SharedModule {}",[],{"id":278,"html":279,"type":124},"b42","\u003Cp>Anything that imports \u003Ccode>SharedModule\u003C\u002Fcode> now has access to whatever \u003Ccode>CacheModule\u003C\u002Fcode> itself exports, without needing to import \u003Ccode>CacheModule\u003C\u002Fcode> directly. This is useful for grouping a handful of foundational modules into one convenience import — but it&#39;s also a coupling decision: every consumer of \u003Ccode>SharedModule\u003C\u002Fcode> now implicitly depends on \u003Ccode>CacheModule\u003C\u002Fcode>&#39;s public surface too, even if they only wanted one of the other things \u003Ccode>SharedModule\u003C\u002Fcode> re-exports.\u003C\u002Fp>",{"id":281,"html":282,"type":124},"b43","\u003Cp>\u003Cstrong>Key concept:\u003C\u002Fstrong> re-exporting is transitive on purpose. Use it to flatten a genuinely related group of modules into one import, not as a way to avoid writing \u003Ccode>imports: [ModuleA, ModuleB, ModuleC]\u003C\u002Fcode> explicitly when the three aren&#39;t actually related.\u003C\u002Fp>",{"id":284,"html":285,"text":286,"type":138,"level":31},"b44","Stage 4: \u003Ccode>@Global()\u003C\u002Fcode> — removing the boundary on purpose","Stage 4: @Global() — removing the boundary on purpose",{"id":288,"html":289,"type":124},"b45","\u003Cp>Some providers really do belong everywhere — a config service, a logger. Re-importing a \u003Ccode>ConfigModule\u003C\u002Fcode> into every single feature module works, but it&#39;s repetitive. \u003Ccode>@Global()\u003C\u002Fcode> exists for exactly this:\u003C\u002Fp>",{"id":291,"code":292,"type":128,"language":190,"highlight":293},"b46","\u002F\u002F config.module.ts\n@Global()\n@Module({\n  providers: [ConfigService],\n  exports: [ConfigService],\n})\nexport class ConfigModule {}",[],{"id":295,"html":296,"type":124},"b47","\u003Cp>Once \u003Ccode>ConfigModule\u003C\u002Fcode> is imported \u003Cem>once\u003C\u002Fem>, anywhere in the module tree (typically \u003Ccode>AppModule\u003C\u002Fcode>), \u003Ccode>ConfigService\u003C\u002Fcode> becomes resolvable from every other module&#39;s injector, with no \u003Ccode>imports: [ConfigModule]\u003C\u002Fcode> needed at each call site. \u003Ccode>@Global()\u003C\u002Fcode> doesn&#39;t skip registration — the module still has to be imported once, and it still has to \u003Ccode>export\u003C\u002Fcode> what it wants global — it only skips the \u003Cem>repeated\u003C\u002Fem> importing everywhere else.\u003C\u002Fp>",{"id":298,"html":299,"type":124},"b48","\u003Cp>This is a real convenience, and it&#39;s also a real cost: every module in the app is now implicitly coupled to that provider, with no \u003Ccode>imports\u003C\u002Fcode> line anywhere marking the dependency. Reading \u003Ccode>OrdersModule\u003C\u002Fcode>&#39;s \u003Ccode>@Module()\u003C\u002Fcode> decorator no longer tells you everything \u003Ccode>OrdersService\u003C\u002Fcode> can inject — some of it is invisible, wired in from wherever \u003Ccode>@Global()\u003C\u002Fcode> was declared. That&#39;s fine for two or three truly cross-cutting providers (config, a logger); it stops being fine the moment \u003Ccode>@Global()\u003C\u002Fcode> becomes the answer to &quot;I don&#39;t want to write another import.&quot;\u003C\u002Fp>",{"id":301,"html":302,"text":302,"type":138,"level":31},"b49","Stage 5: dynamic modules follow the same rules",{"id":304,"html":305,"type":124},"b50","\u003Cp>\u003Ccode>forRoot()\u003C\u002Fcode> and \u003Ccode>forFeature()\u003C\u002Fcode> — the pattern behind \u003Ccode>ConfigModule.forRoot(...)\u003C\u002Fcode>, \u003Ccode>TypeOrmModule.forFeature([...])\u003C\u002Fcode>, and most third-party Nest modules — are just regular functions that return a module definition object at runtime instead of a static \u003Ccode>@Module()\u003C\u002Fcode> class body:\u003C\u002Fp>",{"id":307,"code":308,"type":128,"language":190,"highlight":309},"b51","@Module({})\nexport class DatabaseModule {\n  static forRoot(options: DatabaseOptions): DynamicModule {\n    return {\n      module: DatabaseModule,\n      providers: [{ provide: 'DB_OPTIONS', useValue: options }, DatabaseService],\n      exports: [DatabaseService],\n    };\n  }\n}",[],{"id":311,"html":312,"type":124},"b52","\u003Cp>Everything from Stages 1–3 applies unchanged: whatever this returns for \u003Ccode>exports\u003C\u002Fcode> is exactly as visible to importers as a static module&#39;s \u003Ccode>exports\u003C\u002Fcode> array, and whatever it leaves out is exactly as private. The only thing dynamic is \u003Cem>when\u003C\u002Fem> the module shape is decided — at \u003Ccode>imports: [DatabaseModule.forRoot({ url: &#39;...&#39; })]\u003C\u002Fcode> time, using arguments the static form can&#39;t accept — not \u003Cem>whether\u003C\u002Fem> encapsulation applies to the result.\u003C\u002Fp>",{"id":314,"html":315,"text":315,"type":138,"level":31},"b53","Stage 6: circular dependencies between modules",{"id":317,"html":318,"type":124},"b54","\u003Cp>Sometimes two modules genuinely need each other — \u003Ccode>UsersModule\u003C\u002Fcode> needs \u003Ccode>PostsModule\u003C\u002Fcode> to look up a user&#39;s posts, and \u003Ccode>PostsModule\u003C\u002Fcode> needs \u003Ccode>UsersModule\u003C\u002Fcode> to look up a post&#39;s author. Importing each other directly deadlocks Nest&#39;s bootstrap: to build \u003Ccode>UsersModule\u003C\u002Fcode> it needs \u003Ccode>PostsModule\u003C\u002Fcode> fully built first, which needs \u003Ccode>UsersModule\u003C\u002Fcode> fully built first.\u003C\u002Fp>",{"id":320,"code":321,"type":128,"language":190,"highlight":322},"b55","\u002F\u002F users.module.ts\n@Module({\n  imports: [forwardRef(() => PostsModule)],\n  exports: [UsersService],\n})\nexport class UsersModule {}",[],{"id":324,"code":325,"type":128,"language":190,"highlight":326},"b56","\u002F\u002F posts.module.ts\n@Module({\n  imports: [forwardRef(() => UsersModule)],\n  exports: [PostsService],\n})\nexport class PostsModule {}",[],{"id":328,"html":329,"type":124},"b57","\u003Cp>\u003Ccode>forwardRef()\u003C\u002Fcode> tells Nest &quot;reference this module, but don&#39;t try to fully resolve it yet&quot; — it breaks the deadlock by deferring the reference instead of demanding it eagerly. Both sides of a module-level circular dependency need \u003Ccode>forwardRef()\u003C\u002Fcode>, not just one; wrapping only one side still leaves the other side trying to eagerly resolve something that isn&#39;t ready.\u003C\u002Fp>",{"id":331,"html":332,"type":124},"b58","\u003Cp>The same tool exists at the provider level, for a circular dependency between two services rather than two modules:\u003C\u002Fp>",{"id":334,"code":335,"type":128,"language":190,"highlight":336},"b59","@Injectable()\nexport class UsersService {\n  constructor(\n    @Inject(forwardRef(() => PostsService))\n    private readonly posts: PostsService,\n  ) {}\n}",[],{"id":338,"html":339,"type":124},"b60","\u003Cp>NestJS&#39;s own documentation is explicit that once \u003Ccode>forwardRef()\u003C\u002Fcode> is involved, \u003Cstrong>the order of instantiation between the two sides is indeterminate\u003C\u002Fstrong> — don&#39;t write constructor logic that assumes one of them is fully ready before the other&#39;s constructor has run.\u003C\u002Fp>",{"id":341,"html":342,"type":124},"b61","\u003Cp>\u003Cstrong>Key concept:\u003C\u002Fstrong> \u003Ccode>forwardRef()\u003C\u002Fcode> is a real fix for a real, occasional need — but a circular dependency between two modules is usually the container telling you two modules are actually one responsibility split awkwardly in half. Before reaching for \u003Ccode>forwardRef()\u003C\u002Fcode>, check whether the piece both sides need (in the example above, &quot;which user wrote which post&quot;) belongs in a third module that both \u003Ccode>UsersModule\u003C\u002Fcode> and \u003Ccode>PostsModule\u003C\u002Fcode> import, with no circle at all.\u003C\u002Fp>",{"id":344,"html":345,"text":345,"type":138,"level":31},"b62","Edge cases and gotchas",{"id":347,"type":144,"items":348,"ordered":18},"b63",[349,350,351,352,353],"\u003Cstrong>A provider registered but not exported fails with the same error as a provider that was never imported at all.\u003C\u002Fstrong> The error message doesn&#39;t distinguish &quot;you forgot \u003Ccode>exports\u003C\u002Fcode>&quot; from &quot;you forgot \u003Ccode>imports\u003C\u002Fcode>&quot; — check both, every time.","\u003Cstrong>Exporting a module you only imported for your own internal use\u003C\u002Fstrong> (Stage 3) accidentally makes it part of your public API. If \u003Ccode>SharedModule\u003C\u002Fcode> re-exports \u003Ccode>CacheModule\u003C\u002Fcode> just because \u003Ccode>SharedModule\u003C\u002Fcode> happens to use caching internally, every consumer of \u003Ccode>SharedModule\u003C\u002Fcode> now depends on \u003Ccode>CacheModule\u003C\u002Fcode> too — audit \u003Ccode>exports\u003C\u002Fcode> for things exported by habit rather than by intent.","\u003Cstrong>Barrel files (\u003Ccode>index.ts\u003C\u002Fcode> re-exporting everything in a directory) can create circular imports Nest didn&#39;t ask for.\u003C\u002Fstrong> Two files that each import from the same barrel, which re-exports both, can produce a TypeScript-level circular import independent of any DI circularity — and it&#39;s easy to mistake for a DI problem. NestJS&#39;s own circular-dependency guidance calls this out specifically: avoid barrel files for imports within the module you&#39;re actively writing.","\u003Cstrong>\u003Ccode>ModuleRef\u003C\u002Fcode> is the escape hatch when \u003Ccode>forwardRef()\u003C\u002Fcode> feels wrong.\u003C\u002Fstrong> Instead of injecting a circular dependency through the constructor, \u003Ccode>ModuleRef.get()\u003C\u002Fcode> (or \u003Ccode>.resolve()\u003C\u002Fcode> for scoped providers) can fetch a provider lazily, after the module has finished initializing — useful when the circularity is real but the two sides don&#39;t actually need each other at construction time, only later.","\u003Cstrong>\u003Ccode>@Global()\u003C\u002Fcode> providers still have exactly one registration.\u003C\u002Fstrong> Making \u003Ccode>ConfigService\u003C\u002Fcode> global doesn&#39;t create one instance per module that uses it — it&#39;s the same singleton-per-registration rule from the DI container, just made reachable without an explicit \u003Ccode>imports\u003C\u002Fcode> line at every call site.",{"id":355,"html":356,"text":356,"type":138,"level":31},"b64","Best practices",{"id":358,"type":144,"items":359,"ordered":18},"b65",[360,361,362,363,364,365],"\u003Cstrong>Export the smallest surface that satisfies every real consumer\u003C\u002Fstrong> — a service, not the repository or config it happens to use internally. Treat \u003Ccode>exports\u003C\u002Fcode> like a public API, because that&#39;s what it is.","\u003Cstrong>Reach for \u003Ccode>@Global()\u003C\u002Fcode> only for genuinely cross-cutting infrastructure\u003C\u002Fstrong> (config, logging, a request-tracing context) — not as a shortcut to avoid a couple of \u003Ccode>imports\u003C\u002Fcode> lines. Every global provider is a dependency \u003Ccode>grep\u003C\u002Fcode>-ing a module&#39;s own file won&#39;t show you.","\u003Cstrong>Treat a module-level circular dependency as a design smell first, a \u003Ccode>forwardRef()\u003C\u002Fcode> problem second.\u003C\u002Fstrong> Look for the shared responsibility that belongs in a third module before wrapping both sides in \u003Ccode>forwardRef()\u003C\u002Fcode>.","\u003Cstrong>When you do need \u003Ccode>forwardRef()\u003C\u002Fcode>, apply it on both sides\u003C\u002Fstrong> of the relationship — module-to-module and, if it&#39;s providers, constructor-to-constructor — and never write code that depends on which one finishes initializing first.","\u003Cstrong>Avoid barrel-file imports inside the module you&#39;re actively editing\u003C\u002Fstrong>, to keep TypeScript-level circular imports from masquerading as DI circularity.","\u003Cstrong>Re-export a module only when you mean to hand its whole public surface to your own consumers\u003C\u002Fstrong> — otherwise import it privately and don&#39;t list it in your own \u003Ccode>exports\u003C\u002Fcode>.",{"id":367,"html":368,"type":124},"b66","\u003C!-- quiz:start -->",{"id":370,"html":371,"text":371,"type":138,"level":31},"b67","🧠 Test yourself",{"id":373,"html":374,"type":124},"b68","\u003Cp>Think it clicked? \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fnestjs-weekly-module-encapsulation-exports\u002Fquiz\">Take the 9-question quiz →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":376,"html":377,"type":124},"b69","\u003Cp>\u003Cem>Instant feedback, a hint on every question, and an explanation for each answer — right or wrong.\u003C\u002Fem>\u003C\u002Fp>",{"id":379,"html":380,"type":124},"b70","\u003C!-- quiz:end -->",{"id":382,"html":383,"text":383,"type":138,"level":31},"b71","FAQ",{"id":385,"html":386,"text":387,"type":138,"level":43},"b72","Why does the error say &quot;can&#39;t resolve dependencies&quot; instead of &quot;not exported&quot;?","Why does the error say \"can't resolve dependencies\" instead of \"not exported\"?",{"id":389,"html":390,"type":124},"b73","\u003Cp>Nest&#39;s resolver doesn&#39;t distinguish the two causes in its message because, from the injector&#39;s point of view, they look identical: the token simply isn&#39;t visible in the context it&#39;s being asked for. Whether the root cause is a missing \u003Ccode>imports\u003C\u002Fcode> or a missing \u003Ccode>exports\u003C\u002Fcode>, check both.\u003C\u002Fp>",{"id":392,"html":393,"text":393,"type":138,"level":43},"b74","Does exporting a provider create a second instance of it?",{"id":395,"html":396,"type":124},"b75","\u003Cp>No. \u003Ccode>exports\u003C\u002Fcode> only changes visibility, not instantiation — the provider is still built once, wherever it&#39;s registered in \u003Ccode>providers\u003C\u002Fcode>. This is the same rule the DI-container episode covers for sharing an instance across modules; \u003Ccode>exports\u003C\u002Fcode> is the mechanism that makes that sharing possible.\u003C\u002Fp>",{"id":398,"html":399,"text":400,"type":138,"level":43},"b76","Can I export a provider I didn&#39;t put in this module&#39;s own \u003Ccode>providers\u003C\u002Fcode>?","Can I export a provider I didn't put in this module's own providers?",{"id":402,"html":403,"type":124},"b77","\u003Cp>No — a module can only export a provider it registered itself, or a whole module it imported (Stage 3&#39;s re-export). You can&#39;t export a provider that belongs to some other module without going through that module&#39;s own module-level export.\u003C\u002Fp>",{"id":405,"html":406,"text":407,"type":138,"level":43},"b78","Is \u003Ccode>@Global()\u003C\u002Fcode> the same as making a provider a true app-wide singleton?","Is @Global() the same as making a provider a true app-wide singleton?",{"id":409,"html":410,"type":124},"b79","\u003Cp>It doesn&#39;t change how many instances exist — a global provider still follows the same \u003Ccode>Scope.DEFAULT\u003C\u002Fcode>\u002F\u003Ccode>REQUEST\u003C\u002Fcode>\u002F\u003Ccode>TRANSIENT\u003C\u002Fcode> rules as any other provider. \u003Ccode>@Global()\u003C\u002Fcode> only changes \u003Cem>visibility\u003C\u002Fem>: every module&#39;s injector can resolve it without an explicit \u003Ccode>imports\u003C\u002Fcode> line.\u003C\u002Fp>",{"id":412,"html":413,"text":414,"type":138,"level":43},"b80","Do I need \u003Ccode>forwardRef()\u003C\u002Fcode> if two providers in the \u003Cem>same\u003C\u002Fem> module depend on each other?","Do I need forwardRef() if two providers in the same module depend on each other?",{"id":416,"html":417,"type":124},"b81","\u003Cp>Yes — the circular dependency is between the two classes, not the modules, so it needs \u003Ccode>@Inject(forwardRef(() =&gt; OtherService))\u003C\u002Fcode> on both constructors regardless of whether they live in the same \u003Ccode>@Module()\u003C\u002Fcode> or different ones.\u003C\u002Fp>",{"id":419,"html":420,"text":420,"type":138,"level":31},"b82","Cheat sheet",{"id":422,"head":423,"rows":427,"type":464},"b83",[424,425,426],"Need","Syntax","Notes",[428,432,436,440,444,448,452,456,460],[429,430,431],"Use a provider only inside its own module","\u003Ccode>providers: [X]\u003C\u002Fcode>","No \u003Ccode>exports\u003C\u002Fcode> needed — nothing outside the module can see it",[433,434,435],"Make a provider visible to importers","\u003Ccode>providers: [X], exports: [X]\u003C\u002Fcode>","Both lines are required; \u003Ccode>providers\u003C\u002Fcode> alone never crosses the boundary",[437,438,439],"Use another module&#39;s exported provider","\u003Ccode>imports: [OtherModule]\u003C\u002Fcode>","Only pulls in what \u003Ccode>OtherModule\u003C\u002Fcode> put in its own \u003Ccode>exports\u003C\u002Fcode>",[441,442,443],"Pass a whole imported module through","\u003Ccode>imports: [X], exports: [X]\u003C\u002Fcode> (a module, not a provider)","Re-export — your consumers get \u003Ccode>X\u003C\u002Fcode>&#39;s exports too, without importing \u003Ccode>X\u003C\u002Fcode> directly",[445,446,447],"Make a provider available everywhere, no repeated imports","\u003Ccode>@Global()\u003C\u002Fcode> on the owning module, still with \u003Ccode>exports: [X]\u003C\u002Fcode>","Import that module once (usually in \u003Ccode>AppModule\u003C\u002Fcode>); costs an invisible, implicit dependency everywhere else",[449,450,451],"Configure a module with runtime arguments","\u003Ccode>static forRoot(options): DynamicModule { return { module, providers, exports } }\u003C\u002Fcode>","Same encapsulation rules apply to the returned object",[453,454,455],"Break a module-level circular import","\u003Ccode>imports: [forwardRef(() =&gt; OtherModule)]\u003C\u002Fcode> on \u003Cstrong>both\u003C\u002Fstrong> modules","Order of instantiation is indeterminate afterward",[457,458,459],"Break a provider-level circular dependency","\u003Ccode>@Inject(forwardRef(() =&gt; OtherService))\u003C\u002Fcode> on \u003Cstrong>both\u003C\u002Fstrong> constructors","Usually a sign a third, shared module is missing",[461,462,463],"Resolve a provider without a constructor-time circular import","\u003Ccode>constructor(private moduleRef: ModuleRef) {}\u003C\u002Fcode> then \u003Ccode>this.moduleRef.get(X)\u003C\u002Fcode>","Fetches lazily, after initialization — sidesteps \u003Ccode>forwardRef()\u003C\u002Fcode> entirely","table",{"id":466,"html":467,"text":467,"type":138,"level":31},"b84","Key takeaways",{"id":469,"type":144,"items":470,"ordered":18},"b85",[471,472,473,474,475],"A NestJS module is a real boundary around its own injector — \u003Ccode>providers\u003C\u002Fcode> decides what a module can build for itself, \u003Ccode>exports\u003C\u002Fcode> decides what it&#39;s willing to hand to importers, and a provider needs both before another module can inject it.","\u003Ccode>imports\u003C\u002Fcode> opens a connection between two modules; it carries nothing by itself. The provider still has to be exported on the other end.","\u003Ccode>@Global()\u003C\u002Fcode> doesn&#39;t remove encapsulation — it removes the need to repeat \u003Ccode>imports\u003C\u002Fcode> everywhere, at the cost of a dependency that no longer shows up in the consuming module&#39;s own file.","Dynamic modules (\u003Ccode>forRoot\u003C\u002Fcode>\u002F\u003Ccode>forFeature\u003C\u002Fcode>) decide their \u003Ccode>providers\u003C\u002Fcode>\u002F\u003Ccode>exports\u003C\u002Fcode> at runtime, but the same visibility rules apply to whatever they return.","A circular dependency between two modules usually means a third module is missing more than it means you need \u003Ccode>forwardRef()\u003C\u002Fcode> — reach for the wrap only after checking for the missing shared piece.",{"id":477,"html":478,"type":124},"b86","\u003Cp>The \u003Ccode>NotificationsService\u003C\u002Fcode> error from the top of this article is a one-line fix — add \u003Ccode>exports: [NotificationsService]\u003C\u002Fcode> — but the message Nest prints doesn&#39;t tell you which half of the contract is missing. Once &quot;a module is a boundary, and only \u003Ccode>exports\u003C\u002Fcode> opens it&quot; replaces &quot;it&#39;s decorated with \u003Ccode>@Injectable()\u003C\u002Fcode>, so it should just work,&quot; that error stops being a mystery and starts being the first thing you check.\u003C\u002Fp>",{"id":480,"html":481,"type":124},"b87","\u003Cp>What&#39;s the module-boundary bug that cost you the most time — a missing export, an accidental \u003Ccode>@Global()\u003C\u002Fcode>, or a circular dependency you routed around with \u003Ccode>forwardRef()\u003C\u002Fcode> instead of fixing? Drop it in the comments.\u003C\u002Fp>",{"id":483,"type":484},"b88","divider",{"id":486,"html":487,"type":124},"b89","\u003Cp>🚀 \u003Cstrong>Want more like this?\u003C\u002Fstrong> Every guide, playground, and quiz lives on \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002F\">bestpractic.org\u003C\u002Fa>\u003C\u002Fstrong> — open it and \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002F\">sign up free\u003C\u002Fa>\u003C\u002Fstrong> so the next one finds you.\u003C\u002Fp>",{"id":489,"html":490,"type":124},"b90","\u003Cp>\u003Cem>Thanks for reading! Let&#39;s stay connected:\u003C\u002Fem>\u003C\u002Fp>",{"id":492,"type":144,"items":493,"ordered":18},"b91",[494,495,496],"⭐ \u003Cstrong>GitHub\u003C\u002Fstrong> — follow me and star the projects: \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fparsajiravand\">github.com\u002Fparsajiravand\u003C\u002Fa>","💬 \u003Cstrong>Discord\u003C\u002Fstrong> — join the frontend best-practices community: \u003Ca href=\"https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ\">discord.gg\u002Fd9KRhuAwQ\u003C\u002Fa>","📸 \u003Cstrong>Instagram\u003C\u002Fstrong> — frontend best practices, daily: \u003Ca href=\"https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F\">@bestpractice___\u003C\u002Fa>","A NestJS app boots cleanly for weeks. Then a teammate adds `NotificationsModule`, wires `NotificationsService` into `OrdersService`'s constructor, runs the app — and Nest refuses to start:\n\n```\nNest can't resolve dependencies of the OrdersService (?). Please make sure that the argument NotificationsService at index [1] is available in the OrdersModule context.\n\nPotential solutions:\n- Is OrdersModule a valid NestJS module?\n- If NotificationsService is exported from a separate @Module, is that module imported within OrdersModule?\n```\n\nNothing about `NotificationsService` itself is wrong — it's decorated with `@Injectable()`, it compiles, its own tests pass in isolation. The teammate even double-checked it's listed in `NotificationsModule`'s `providers` array. It is. That's not the part that's missing.\n\n## What you'll learn\n\nBy the end of this article you'll be able to:\n\n- Explain what a NestJS module boundary actually is, and why \"it's in `providers`\" isn't the same question as \"can this other module see it\"\n- Fix the exact error above by understanding what `exports` really crosses\n- Decide when `@Global()` is the right tool, and why it's the exception, not the default\n- Recognize a module-level circular dependency and choose between `forwardRef()` and the better fix: restructuring\n- Read a dynamic module (`forRoot`\u002F`forFeature`) as the same encapsulation rules, just built at runtime\n\n## Who this is for\n\nYou've built at least one multi-module NestJS app — a couple of feature modules, each with its own controller and service. You don't need to have hit the error above yet; we'll build it from nothing and then fix it properly.\n\nThis article is written against **NestJS 12.x** (verified against the `nestjs\u002Fnest` GitHub release history — `v12.0.0` shipped August 27, 2026). Module registration, `exports`, `@Global()`, and `forwardRef()` are core-container behavior, unchanged in shape across the 10.x → 12.x line.\n\nIf you haven't read it yet, the previous episode covers [how the DI container resolves providers and what \"singleton\" really means](https:\u002F\u002Fdev.to\u002Fparsajiravand\u002Fnestjs-dependency-injection-explained-with-cheat-sheet) — this article assumes that mental model and builds the module-level picture on top of it, but you don't need it to follow along here.\n\n## Table of contents\n\n- [The problem: exported everywhere, visible nowhere](#the-problem-exported-everywhere-visible-nowhere)\n- [The mental model: a module is a boundary, not a folder](#the-mental-model-a-module-is-a-boundary-not-a-folder)\n- [Stage 1: the smallest module boundary](#stage-1-the-smallest-module-boundary)\n- [Stage 2: exports — what actually crosses the boundary](#stage-2-exports-what-actually-crosses-the-boundary)\n- [Stage 3: re-exporting — passing a module through](#stage-3-re-exporting-passing-a-module-through)\n- [Stage 4: `@Global()` — removing the boundary on purpose](#stage-4-global-removing-the-boundary-on-purpose)\n- [Stage 5: dynamic modules follow the same rules](#stage-5-dynamic-modules-follow-the-same-rules)\n- [Stage 6: circular dependencies between modules](#stage-6-circular-dependencies-between-modules)\n- [Edge cases and gotchas](#edge-cases-and-gotchas)\n- [Best practices](#best-practices)\n- [FAQ](#faq)\n- [Cheat sheet](#cheat-sheet)\n\n## The problem: exported everywhere, visible nowhere\n\nHere's the setup, trimmed to the part that matters:\n\n```ts\n\u002F\u002F notifications.service.ts\n@Injectable()\nexport class NotificationsService {\n  send(userId: string, message: string) {\n    \u002F\u002F ...\n  }\n}\n```\n\n```ts\n\u002F\u002F notifications.module.ts\n@Module({\n  providers: [NotificationsService],\n})\nexport class NotificationsModule {}\n```\n\n```ts\n\u002F\u002F orders.module.ts\n@Module({\n  imports: [NotificationsModule],\n  controllers: [OrdersController],\n  providers: [OrdersService],\n})\nexport class OrdersModule {}\n```\n\n```ts\n\u002F\u002F orders.service.ts\n@Injectable()\nexport class OrdersService {\n  constructor(\n    private readonly repo: OrdersRepository,\n    private readonly notifications: NotificationsService, \u002F\u002F ← this is what fails\n  ) {}\n}\n```\n\nEverything here looks correct by the checklist most people carry around: `@Injectable()` on the service, listed in a module's `providers`, that module imported by the consumer. And yet Nest still can't resolve it — because the checklist is missing one line: `NotificationsModule` never says `exports: [NotificationsService]`.\n\n## The mental model: a module is a boundary, not a folder\n\n**The mental model:** a NestJS module isn't an organizational folder — it's a real wall around a slice of the DI container. Each module gets its own injector, and that injector only knows two kinds of providers: the ones listed directly in its own `providers` array, and the ones explicitly handed to it through `imports` — and only the subset of *those* that the imported module put in its own `exports` array.\n\n`providers` answers \"what can this module build?\" `exports` answers a completely different question: \"what am I willing to hand to whoever imports me?\" A provider can be fully registered and working *inside* its own module and still be completely invisible to every other module, because `providers` alone doesn't open the wall — only `exports` does.\n\nThat's exactly the gap in the bug above: `NotificationsModule` builds `NotificationsService` correctly for its own internal use, but never lists it in `exports`. `OrdersModule` imports `NotificationsModule` — establishing an edge in the module graph — but that edge carries nothing across it, because the sending side never put anything on the wire.\n\n```ts\n\u002F\u002F notifications.module.ts — the fix\n@Module({\n  providers: [NotificationsService],\n  exports: [NotificationsService], \u002F\u002F now it can leave this module\n})\nexport class NotificationsModule {}\n```\n\n**Key concept:** `imports` opens a door between two modules; `exports` decides what's allowed to walk through it. A provider needs both — registered somewhere, and exported from wherever it's registered — before another module's injector can see it, no matter how correctly it's decorated.\n\n\u003C!-- playground:start -->\n\n## 🎮 Try it yourself\n\n**[▶️ Open the interactive playground →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fnestjs-weekly-module-encapsulation-exports\u002Fplayground)**\n\n_Runs right in your browser — poke at it and watch the concept react live._\n\n\u003C!-- playground:end -->\n\n## Stage 1: the smallest module boundary\n\nA module with nothing exported is still a perfectly valid, fully functional module — for its own controllers and services:\n\n```ts\n@Module({\n  controllers: [OrdersController],\n  providers: [OrdersService, OrdersRepository],\n})\nexport class OrdersModule {}\n```\n\n`OrdersController` and `OrdersService` can inject `OrdersRepository` freely — they're all in the same injector. Nothing here needs an export, because nothing here needs to leave the module. The boundary only becomes visible the moment something *outside* `OrdersModule` wants in.\n\n## Stage 2: exports — what actually crosses the boundary\n\n`exports` takes a subset of what's in `providers` (or a whole imported module — see the next stage) and makes it resolvable by any module that lists this one in its own `imports`:\n\n```ts\n@Module({\n  providers: [OrdersService, OrdersRepository],\n  exports: [OrdersService], \u002F\u002F OrdersRepository stays private\n})\nexport class OrdersModule {}\n```\n\nOnly `OrdersService` is importable from elsewhere. `OrdersRepository` is an implementation detail — other modules that import `OrdersModule` get access to the service's public surface, not the repository it happens to use internally. This is deliberate, and it's the same instinct as a private class member: export the smallest set that satisfies every real consumer.\n\n## Stage 3: re-exporting — passing a module through\n\nA module can also export a module it imported, without re-listing its individual providers — this passes the whole thing through:\n\n```ts\n\u002F\u002F shared.module.ts\n@Module({\n  imports: [CacheModule],\n  exports: [CacheModule], \u002F\u002F re-export: anyone importing SharedModule also gets CacheModule's exports\n})\nexport class SharedModule {}\n```\n\nAnything that imports `SharedModule` now has access to whatever `CacheModule` itself exports, without needing to import `CacheModule` directly. This is useful for grouping a handful of foundational modules into one convenience import — but it's also a coupling decision: every consumer of `SharedModule` now implicitly depends on `CacheModule`'s public surface too, even if they only wanted one of the other things `SharedModule` re-exports.\n\n**Key concept:** re-exporting is transitive on purpose. Use it to flatten a genuinely related group of modules into one import, not as a way to avoid writing `imports: [ModuleA, ModuleB, ModuleC]` explicitly when the three aren't actually related.\n\n## Stage 4: `@Global()` — removing the boundary on purpose\n\nSome providers really do belong everywhere — a config service, a logger. Re-importing a `ConfigModule` into every single feature module works, but it's repetitive. `@Global()` exists for exactly this:\n\n```ts\n\u002F\u002F config.module.ts\n@Global()\n@Module({\n  providers: [ConfigService],\n  exports: [ConfigService],\n})\nexport class ConfigModule {}\n```\n\nOnce `ConfigModule` is imported *once*, anywhere in the module tree (typically `AppModule`), `ConfigService` becomes resolvable from every other module's injector, with no `imports: [ConfigModule]` needed at each call site. `@Global()` doesn't skip registration — the module still has to be imported once, and it still has to `export` what it wants global — it only skips the *repeated* importing everywhere else.\n\nThis is a real convenience, and it's also a real cost: every module in the app is now implicitly coupled to that provider, with no `imports` line anywhere marking the dependency. Reading `OrdersModule`'s `@Module()` decorator no longer tells you everything `OrdersService` can inject — some of it is invisible, wired in from wherever `@Global()` was declared. That's fine for two or three truly cross-cutting providers (config, a logger); it stops being fine the moment `@Global()` becomes the answer to \"I don't want to write another import.\"\n\n## Stage 5: dynamic modules follow the same rules\n\n`forRoot()` and `forFeature()` — the pattern behind `ConfigModule.forRoot(...)`, `TypeOrmModule.forFeature([...])`, and most third-party Nest modules — are just regular functions that return a module definition object at runtime instead of a static `@Module()` class body:\n\n```ts\n@Module({})\nexport class DatabaseModule {\n  static forRoot(options: DatabaseOptions): DynamicModule {\n    return {\n      module: DatabaseModule,\n      providers: [{ provide: 'DB_OPTIONS', useValue: options }, DatabaseService],\n      exports: [DatabaseService],\n    };\n  }\n}\n```\n\nEverything from Stages 1–3 applies unchanged: whatever this returns for `exports` is exactly as visible to importers as a static module's `exports` array, and whatever it leaves out is exactly as private. The only thing dynamic is *when* the module shape is decided — at `imports: [DatabaseModule.forRoot({ url: '...' })]` time, using arguments the static form can't accept — not *whether* encapsulation applies to the result.\n\n## Stage 6: circular dependencies between modules\n\nSometimes two modules genuinely need each other — `UsersModule` needs `PostsModule` to look up a user's posts, and `PostsModule` needs `UsersModule` to look up a post's author. Importing each other directly deadlocks Nest's bootstrap: to build `UsersModule` it needs `PostsModule` fully built first, which needs `UsersModule` fully built first.\n\n```ts\n\u002F\u002F users.module.ts\n@Module({\n  imports: [forwardRef(() => PostsModule)],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n```\n\n```ts\n\u002F\u002F posts.module.ts\n@Module({\n  imports: [forwardRef(() => UsersModule)],\n  exports: [PostsService],\n})\nexport class PostsModule {}\n```\n\n`forwardRef()` tells Nest \"reference this module, but don't try to fully resolve it yet\" — it breaks the deadlock by deferring the reference instead of demanding it eagerly. Both sides of a module-level circular dependency need `forwardRef()`, not just one; wrapping only one side still leaves the other side trying to eagerly resolve something that isn't ready.\n\nThe same tool exists at the provider level, for a circular dependency between two services rather than two modules:\n\n```ts\n@Injectable()\nexport class UsersService {\n  constructor(\n    @Inject(forwardRef(() => PostsService))\n    private readonly posts: PostsService,\n  ) {}\n}\n```\n\nNestJS's own documentation is explicit that once `forwardRef()` is involved, **the order of instantiation between the two sides is indeterminate** — don't write constructor logic that assumes one of them is fully ready before the other's constructor has run.\n\n**Key concept:** `forwardRef()` is a real fix for a real, occasional need — but a circular dependency between two modules is usually the container telling you two modules are actually one responsibility split awkwardly in half. Before reaching for `forwardRef()`, check whether the piece both sides need (in the example above, \"which user wrote which post\") belongs in a third module that both `UsersModule` and `PostsModule` import, with no circle at all.\n\n## Edge cases and gotchas\n\n- **A provider registered but not exported fails with the same error as a provider that was never imported at all.** The error message doesn't distinguish \"you forgot `exports`\" from \"you forgot `imports`\" — check both, every time.\n- **Exporting a module you only imported for your own internal use** (Stage 3) accidentally makes it part of your public API. If `SharedModule` re-exports `CacheModule` just because `SharedModule` happens to use caching internally, every consumer of `SharedModule` now depends on `CacheModule` too — audit `exports` for things exported by habit rather than by intent.\n- **Barrel files (`index.ts` re-exporting everything in a directory) can create circular imports Nest didn't ask for.** Two files that each import from the same barrel, which re-exports both, can produce a TypeScript-level circular import independent of any DI circularity — and it's easy to mistake for a DI problem. NestJS's own circular-dependency guidance calls this out specifically: avoid barrel files for imports within the module you're actively writing.\n- **`ModuleRef` is the escape hatch when `forwardRef()` feels wrong.** Instead of injecting a circular dependency through the constructor, `ModuleRef.get()` (or `.resolve()` for scoped providers) can fetch a provider lazily, after the module has finished initializing — useful when the circularity is real but the two sides don't actually need each other at construction time, only later.\n- **`@Global()` providers still have exactly one registration.** Making `ConfigService` global doesn't create one instance per module that uses it — it's the same singleton-per-registration rule from the DI container, just made reachable without an explicit `imports` line at every call site.\n\n## Best practices\n\n- **Export the smallest surface that satisfies every real consumer** — a service, not the repository or config it happens to use internally. Treat `exports` like a public API, because that's what it is.\n- **Reach for `@Global()` only for genuinely cross-cutting infrastructure** (config, logging, a request-tracing context) — not as a shortcut to avoid a couple of `imports` lines. Every global provider is a dependency `grep`-ing a module's own file won't show you.\n- **Treat a module-level circular dependency as a design smell first, a `forwardRef()` problem second.** Look for the shared responsibility that belongs in a third module before wrapping both sides in `forwardRef()`.\n- **When you do need `forwardRef()`, apply it on both sides** of the relationship — module-to-module and, if it's providers, constructor-to-constructor — and never write code that depends on which one finishes initializing first.\n- **Avoid barrel-file imports inside the module you're actively editing**, to keep TypeScript-level circular imports from masquerading as DI circularity.\n- **Re-export a module only when you mean to hand its whole public surface to your own consumers** — otherwise import it privately and don't list it in your own `exports`.\n\n\u003C!-- quiz:start -->\n\n## 🧠 Test yourself\n\nThink it clicked? **[Take the 9-question quiz →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fnestjs-weekly-module-encapsulation-exports\u002Fquiz)**\n\n_Instant feedback, a hint on every question, and an explanation for each answer — right or wrong._\n\n\u003C!-- quiz:end -->\n\n## FAQ\n\n### Why does the error say \"can't resolve dependencies\" instead of \"not exported\"?\n\nNest's resolver doesn't distinguish the two causes in its message because, from the injector's point of view, they look identical: the token simply isn't visible in the context it's being asked for. Whether the root cause is a missing `imports` or a missing `exports`, check both.\n\n### Does exporting a provider create a second instance of it?\n\nNo. `exports` only changes visibility, not instantiation — the provider is still built once, wherever it's registered in `providers`. This is the same rule the DI-container episode covers for sharing an instance across modules; `exports` is the mechanism that makes that sharing possible.\n\n### Can I export a provider I didn't put in this module's own `providers`?\n\nNo — a module can only export a provider it registered itself, or a whole module it imported (Stage 3's re-export). You can't export a provider that belongs to some other module without going through that module's own module-level export.\n\n### Is `@Global()` the same as making a provider a true app-wide singleton?\n\nIt doesn't change how many instances exist — a global provider still follows the same `Scope.DEFAULT`\u002F`REQUEST`\u002F`TRANSIENT` rules as any other provider. `@Global()` only changes *visibility*: every module's injector can resolve it without an explicit `imports` line.\n\n### Do I need `forwardRef()` if two providers in the *same* module depend on each other?\n\nYes — the circular dependency is between the two classes, not the modules, so it needs `@Inject(forwardRef(() => OtherService))` on both constructors regardless of whether they live in the same `@Module()` or different ones.\n\n## Cheat sheet\n\n| Need | Syntax | Notes |\n| --- | --- | --- |\n| Use a provider only inside its own module | `providers: [X]` | No `exports` needed — nothing outside the module can see it |\n| Make a provider visible to importers | `providers: [X], exports: [X]` | Both lines are required; `providers` alone never crosses the boundary |\n| Use another module's exported provider | `imports: [OtherModule]` | Only pulls in what `OtherModule` put in its own `exports` |\n| Pass a whole imported module through | `imports: [X], exports: [X]` (a module, not a provider) | Re-export — your consumers get `X`'s exports too, without importing `X` directly |\n| Make a provider available everywhere, no repeated imports | `@Global()` on the owning module, still with `exports: [X]` | Import that module once (usually in `AppModule`); costs an invisible, implicit dependency everywhere else |\n| Configure a module with runtime arguments | `static forRoot(options): DynamicModule { return { module, providers, exports } }` | Same encapsulation rules apply to the returned object |\n| Break a module-level circular import | `imports: [forwardRef(() => OtherModule)]` on **both** modules | Order of instantiation is indeterminate afterward |\n| Break a provider-level circular dependency | `@Inject(forwardRef(() => OtherService))` on **both** constructors | Usually a sign a third, shared module is missing |\n| Resolve a provider without a constructor-time circular import | `constructor(private moduleRef: ModuleRef) {}` then `this.moduleRef.get(X)` | Fetches lazily, after initialization — sidesteps `forwardRef()` entirely |\n\n## Key takeaways\n\n- A NestJS module is a real boundary around its own injector — `providers` decides what a module can build for itself, `exports` decides what it's willing to hand to importers, and a provider needs both before another module can inject it.\n- `imports` opens a connection between two modules; it carries nothing by itself. The provider still has to be exported on the other end.\n- `@Global()` doesn't remove encapsulation — it removes the need to repeat `imports` everywhere, at the cost of a dependency that no longer shows up in the consuming module's own file.\n- Dynamic modules (`forRoot`\u002F`forFeature`) decide their `providers`\u002F`exports` at runtime, but the same visibility rules apply to whatever they return.\n- A circular dependency between two modules usually means a third module is missing more than it means you need `forwardRef()` — reach for the wrap only after checking for the missing shared piece.\n\nThe `NotificationsService` error from the top of this article is a one-line fix — add `exports: [NotificationsService]` — but the message Nest prints doesn't tell you which half of the contract is missing. Once \"a module is a boundary, and only `exports` opens it\" replaces \"it's decorated with `@Injectable()`, so it should just work,\" that error stops being a mystery and starts being the first thing you check.\n\nWhat's the module-boundary bug that cost you the most time — a missing export, an accidental `@Global()`, or a circular dependency you routed around with `forwardRef()` instead of fixing? Drop it in the comments.\n\n---\n\n🚀 **Want more like this?** Every guide, playground, and quiz lives on **[bestpractic.org](https:\u002F\u002Fbestpractic.org\u002F)** — open it and **[sign up free](https:\u002F\u002Fbestpractic.org\u002F)** so the next one finds you.\n\n*Thanks for reading! Let's stay connected:*\n\n- ⭐ **GitHub** — follow me and star the projects: [github.com\u002Fparsajiravand](https:\u002F\u002Fgithub.com\u002Fparsajiravand)\n- 💬 **Discord** — join the frontend best-practices community: [discord.gg\u002Fd9KRhuAwQ](https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ)\n- 📸 **Instagram** — frontend best practices, daily: [@bestpractice___](https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F)",{"title":94,"canonical":499,"description":96},"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fnestjs-weekly-module-encapsulation-exports","01a0821b-4733-762d-bf96-bafda1c2d187",{"name":502,"part":31,"total":31,"items":503},"NestJS Deep Dive",[504,509],{"slug":505,"title":506,"publishedAt":507,"readingMinutes":508},"nestjs-weekly-request-lifecycle","NestJS Request Lifecycle Explained (with Cheat Sheet)","2026-08-28T17:01:41.941Z",13,{"slug":93,"title":94,"publishedAt":99,"readingMinutes":98},{"id":511,"locked":18},"01a0821b-4766-760f-b88b-f6a7b438b10b",[513],{"id":514,"slug":93,"title":515,"_count":516},"01a0821b-4793-71d0-bac6-c03b76f33016","NestJS Module Encapsulation",{"questions":517},9,[519],{"locale":13,"slug":93},{"id":514,"slug":93,"title":515,"_count":521,"questionCount":517},{"questions":517},{"items":523,"meta":551},[524,536],{"id":92,"slug":93,"title":94,"subtitle":95,"excerpt":96,"coverUrl":97,"locale":13,"readingMinutes":98,"publishedAt":99,"viewCount":525,"likeCount":19,"commentCount":19,"author":526,"vertical":527,"topic":528,"tags":529,"_count":534,"playground":535,"hasQuiz":17,"hasPlayground":17},30,{"id":102,"name":103,"username":104,"avatarUrl":95,"headline":105},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":108,"name":109},[530,531,532,533],{"slug":108,"name":109,"color":95},{"slug":81,"name":82,"color":95},{"slug":66,"name":67,"color":95},{"slug":62,"name":63,"color":95},{"assessments":116},{"slug":93},{"id":537,"slug":505,"title":506,"subtitle":95,"excerpt":538,"coverUrl":539,"locale":13,"readingMinutes":508,"publishedAt":507,"viewCount":540,"likeCount":19,"commentCount":19,"author":541,"vertical":542,"topic":543,"tags":544,"_count":549,"playground":550,"hasQuiz":17,"hasPlayground":17},"01a03cdb-22ef-748a-b555-8071c7a905e6","A complete guide to the NestJS request lifecycle: the exact order middleware, guards, interceptors, pipes, and filters run, and why it matters.","\u002Fmedia\u002Fcovers\u002Fnestjs-weekly-request-lifecycle.png",261,{"id":102,"name":103,"username":104,"avatarUrl":95,"headline":105},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":108,"name":109},[545,546,547,548],{"slug":108,"name":109,"color":95},{"slug":81,"name":82,"color":95},{"slug":66,"name":67,"color":95},{"slug":62,"name":63,"color":95},{"assessments":116},{"slug":505},{"page":116,"perPage":79,"total":31,"totalPages":116},"\u003Cdiv class=\"shj shj-lang-plain shj-multiline\" data-lang=\"plain\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">Nest can't resolve dependencies of the OrdersService (?). Please make sure that the argument NotificationsService at index [1] is available in the OrdersModule context.\n\nPotential solutions:\n- Is OrdersModule a valid NestJS module?\n- If NotificationsService is exported from a separate @Module, is that module imported within OrdersModule?\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-ts shj-multiline\" data-lang=\"ts\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-cmnt\">\u002F\u002F notifications.service.ts\n\u003C\u002Fspan>@\u003Cspan class=\"shj-class\">Injectable\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\n\u003Cspan class=\"shj-kwd\">export\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">class\u003C\u002Fspan> \u003Cspan class=\"shj-class\">NotificationsService\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-func\">send\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>userId\u003Cspan class=\"shj-type\">: string\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> message\u003Cspan class=\"shj-type\">: string\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n    \u003Cspan class=\"shj-cmnt\">\u002F\u002F ...\n\u003C\u002Fspan>  \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-ts shj-multiline\" data-lang=\"ts\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-cmnt\">\u002F\u002F notifications.module.ts\n\u003C\u002Fspan>@\u003Cspan class=\"shj-class\">Module\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  providers\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">NotificationsService\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\n\u003Cspan class=\"shj-kwd\">export\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">class\u003C\u002Fspan> \u003Cspan class=\"shj-class\">NotificationsModule\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-ts shj-multiline\" data-lang=\"ts\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-cmnt\">\u002F\u002F orders.module.ts\n\u003C\u002Fspan>@\u003Cspan class=\"shj-class\">Module\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  imports\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">NotificationsModule\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n  controllers\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">OrdersController\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n  providers\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">OrdersService\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\n\u003Cspan class=\"shj-kwd\">export\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">class\u003C\u002Fspan> \u003Cspan class=\"shj-class\">OrdersModule\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-ts shj-multiline\" data-lang=\"ts\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003Cdiv>8\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-cmnt\">\u002F\u002F orders.service.ts\n\u003C\u002Fspan>@\u003Cspan class=\"shj-class\">Injectable\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\n\u003Cspan class=\"shj-kwd\">export\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">class\u003C\u002Fspan> \u003Cspan class=\"shj-class\">OrdersService\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-kwd\">constructor\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\n    \u003Cspan class=\"shj-kwd\">private\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">readonly\u003C\u002Fspan> repo\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-class\">OrdersRepository\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n    \u003Cspan class=\"shj-kwd\">private\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">readonly\u003C\u002Fspan> notifications\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-class\">NotificationsService\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-cmnt\">\u002F\u002F ← this is what fails\n\u003C\u002Fspan>  \u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-ts shj-multiline\" data-lang=\"ts\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-cmnt\">\u002F\u002F notifications.module.ts — the fix\n\u003C\u002Fspan>@\u003Cspan class=\"shj-class\">Module\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  providers\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">NotificationsService\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n  exports\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">NotificationsService\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-cmnt\">\u002F\u002F now it can leave this module\n\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\n\u003Cspan class=\"shj-kwd\">export\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">class\u003C\u002Fspan> \u003Cspan class=\"shj-class\">NotificationsModule\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-ts shj-multiline\" data-lang=\"ts\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">@\u003Cspan class=\"shj-class\">Module\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  controllers\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">OrdersController\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n  providers\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">OrdersService\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-class\">OrdersRepository\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\n\u003Cspan class=\"shj-kwd\">export\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">class\u003C\u002Fspan> \u003Cspan class=\"shj-class\">OrdersModule\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-ts shj-multiline\" data-lang=\"ts\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">@\u003Cspan class=\"shj-class\">Module\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  providers\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">OrdersService\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-class\">OrdersRepository\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n  exports\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">OrdersService\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-cmnt\">\u002F\u002F OrdersRepository stays private\n\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\n\u003Cspan class=\"shj-kwd\">export\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">class\u003C\u002Fspan> \u003Cspan class=\"shj-class\">OrdersModule\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-ts shj-multiline\" data-lang=\"ts\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-cmnt\">\u002F\u002F shared.module.ts\n\u003C\u002Fspan>@\u003Cspan class=\"shj-class\">Module\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  imports\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">CacheModule\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n  exports\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">CacheModule\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-cmnt\">\u002F\u002F re-export: anyone importing SharedModule also gets CacheModule's exports\n\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\n\u003Cspan class=\"shj-kwd\">export\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">class\u003C\u002Fspan> \u003Cspan class=\"shj-class\">SharedModule\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-ts shj-multiline\" data-lang=\"ts\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-cmnt\">\u002F\u002F config.module.ts\n\u003C\u002Fspan>@\u003Cspan class=\"shj-class\">Global\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\n@\u003Cspan class=\"shj-class\">Module\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  providers\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">ConfigService\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n  exports\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">ConfigService\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\n\u003Cspan class=\"shj-kwd\">export\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">class\u003C\u002Fspan> \u003Cspan class=\"shj-class\">ConfigModule\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-ts shj-multiline\" data-lang=\"ts\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003Cdiv>8\u003C\u002Fdiv>\u003Cdiv>9\u003C\u002Fdiv>\u003Cdiv>10\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">@\u003Cspan class=\"shj-class\">Module\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\n\u003Cspan class=\"shj-kwd\">export\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">class\u003C\u002Fspan> \u003Cspan class=\"shj-class\">DatabaseModule\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-kwd\">static\u003C\u002Fspan> \u003Cspan class=\"shj-func\">forRoot\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>options\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-class\">DatabaseOptions\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-class\">DynamicModule\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n    \u003Cspan class=\"shj-kwd\">return\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n      module\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-class\">DatabaseModule\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n      providers\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> provide\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-str\">'DB_OPTIONS'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> useValue\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> options \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-class\">DatabaseService\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n      exports\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">DatabaseService\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n    \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-ts shj-multiline\" data-lang=\"ts\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-cmnt\">\u002F\u002F users.module.ts\n\u003C\u002Fspan>@\u003Cspan class=\"shj-class\">Module\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  imports\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-func\">forwardRef\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> \u003Cspan class=\"shj-class\">PostsModule\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n  exports\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">UsersService\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\n\u003Cspan class=\"shj-kwd\">export\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">class\u003C\u002Fspan> \u003Cspan class=\"shj-class\">UsersModule\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-ts shj-multiline\" data-lang=\"ts\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-cmnt\">\u002F\u002F posts.module.ts\n\u003C\u002Fspan>@\u003Cspan class=\"shj-class\">Module\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  imports\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-func\">forwardRef\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> \u003Cspan class=\"shj-class\">UsersModule\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n  exports\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-class\">PostsService\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\n\u003Cspan class=\"shj-kwd\">export\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">class\u003C\u002Fspan> \u003Cspan class=\"shj-class\">PostsModule\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-ts shj-multiline\" data-lang=\"ts\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">@\u003Cspan class=\"shj-class\">Injectable\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\n\u003Cspan class=\"shj-kwd\">export\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">class\u003C\u002Fspan> \u003Cspan class=\"shj-class\">UsersService\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-kwd\">constructor\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\n    @\u003Cspan class=\"shj-class\">Inject\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-func\">forwardRef\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> \u003Cspan class=\"shj-class\">PostsService\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\n    \u003Cspan class=\"shj-kwd\">private\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">readonly\u003C\u002Fspan> posts\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-class\">PostsService\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n  \u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>",{"locked":18,"total":19,"comments":567},[]]