<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: kirandeepjassal-crypto</title>
    <description>The latest articles on DEV Community by kirandeepjassal-crypto (@kirandeepjassalcrypto).</description>
    <link>https://dev.to/kirandeepjassalcrypto</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3948965%2F92a8ebec-5c78-46dc-b19b-babd45c794b0.png</url>
      <title>DEV Community: kirandeepjassal-crypto</title>
      <link>https://dev.to/kirandeepjassalcrypto</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kirandeepjassalcrypto"/>
    <language>en</language>
    <item>
      <title>JavaScript Interview Questions for Senior Developers in 2026 — Closures, the Event Loop, Prototypes &amp; Async</title>
      <dc:creator>kirandeepjassal-crypto</dc:creator>
      <pubDate>Fri, 23 Oct 2026 09:17:36 +0000</pubDate>
      <link>https://dev.to/kirandeepjassalcrypto/javascript-interview-questions-for-senior-developers-in-2026-closures-the-event-loop-prototypes-503m</link>
      <guid>https://dev.to/kirandeepjassalcrypto/javascript-interview-questions-for-senior-developers-in-2026-closures-the-event-loop-prototypes-503m</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Junior JavaScript interviews ask "what does &lt;code&gt;var&lt;/code&gt; do." Senior interviews ask &lt;em&gt;why all your click handlers log the same number&lt;/em&gt;, &lt;em&gt;why a &lt;code&gt;Promise.then&lt;/code&gt; runs before a &lt;code&gt;setTimeout(0)&lt;/code&gt;&lt;/em&gt;, and &lt;em&gt;why your single-page app's memory climbs until the tab crashes after an hour&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;JavaScript looks forgiving and turns out to be full of sharp edges — closures, &lt;code&gt;this&lt;/code&gt;, the event loop, and the ways a long-lived SPA leaks memory — exactly where senior work lives. Seniority is knowing what the engine actually does, not just what the syntax says.&lt;/p&gt;

&lt;p&gt;This is 30 questions across &lt;strong&gt;scope &amp;amp; closures, this &amp;amp; prototypes, async &amp;amp; the event loop, and functional patterns, memory &amp;amp; modern JS&lt;/strong&gt;. Each has a short answer, a deep dive with code, and the senior signal the interviewer is listening for. Examples are grounded in &lt;strong&gt;Mattrx&lt;/strong&gt; — a real long-lived React SPA where memory, the event loop, and bundle size are daily concerns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block A — scope, closures &amp;amp; types
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. var vs let vs const — what's actually different?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;var&lt;/code&gt; is function-scoped and hoisted (initialized &lt;code&gt;undefined&lt;/code&gt;); &lt;code&gt;let&lt;/code&gt;/&lt;code&gt;const&lt;/code&gt; are block-scoped and live in the temporal dead zone until their declaration (accessing early throws). &lt;code&gt;const&lt;/code&gt; binding can't be reassigned (the value can still mutate). Default to &lt;code&gt;const&lt;/code&gt;, use &lt;code&gt;let&lt;/code&gt; when you must reassign, never &lt;code&gt;var&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What is a closure, and why is it useful?&lt;/strong&gt;&lt;br&gt;
A function that remembers the variables of the scope it was created in, even after that scope returned — a live reference, not a copy. It's how JS does private state, factories, memoization, and every hook/callback that captures a value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;makeCounter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                       &lt;span class="c1"&gt;// captured, kept alive by the closures below&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;makeCounter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 2  — count survives after makeCounter() returned&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Why do all my loop handlers log the same number?&lt;/strong&gt;&lt;br&gt;
With &lt;code&gt;var&lt;/code&gt;, the loop variable is one function-scoped binding shared by every closure — by the time the handlers run, the loop has finished and they all read the final value. &lt;code&gt;let&lt;/code&gt; creates a fresh binding per iteration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BUG: var is function-scoped -&amp;gt; every handler closes over the SAME i.&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;buttons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;buttons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;onclick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// always logs buttons.length&lt;/span&gt;

&lt;span class="c1"&gt;// FIX: let is block-scoped -&amp;gt; a new binding each iteration.&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;buttons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;buttons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;onclick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// logs 0, 1, 2, ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. How does hoisting work?&lt;/strong&gt;&lt;br&gt;
Declarations are processed before code runs. &lt;code&gt;function&lt;/code&gt; declarations hoist fully (callable before their line). &lt;code&gt;var&lt;/code&gt; hoists the binding but not the value (reads &lt;code&gt;undefined&lt;/code&gt; early). &lt;code&gt;let&lt;/code&gt;/&lt;code&gt;const&lt;/code&gt; hoist into the TDZ. It's scope setup, not "code moves up."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. == vs === — and when is == ever okay?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;===&lt;/code&gt; compares value and type, no coercion. &lt;code&gt;==&lt;/code&gt; coerces first, with surprising rules. Default to &lt;code&gt;===&lt;/code&gt;. The one common &lt;code&gt;==&lt;/code&gt; idiom: &lt;code&gt;x == null&lt;/code&gt; to catch both &lt;code&gt;null&lt;/code&gt; and &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Primitives vs reference types — how are they passed?&lt;/strong&gt;&lt;br&gt;
Primitives are copied by value. Objects/arrays/functions are held by reference — passing one copies the reference, so mutations inside are visible outside. JS is always pass-by-value; the value of an object is its reference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. null vs undefined vs NaN?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;undefined&lt;/code&gt; = exists but no value (uninitialized, missing arg). &lt;code&gt;null&lt;/code&gt; = an intentional "no value" you assigned. &lt;code&gt;NaN&lt;/code&gt; = result of an invalid numeric op, and &lt;code&gt;NaN !== NaN&lt;/code&gt; (use &lt;code&gt;Number.isNaN&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. How do you reliably check a value's type?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;typeof&lt;/code&gt; for primitives (but &lt;code&gt;typeof null === 'object'&lt;/code&gt; is a historical bug), &lt;code&gt;Array.isArray()&lt;/code&gt; for arrays, &lt;code&gt;instanceof&lt;/code&gt; for class instances (fails across realms), and &lt;code&gt;Object.prototype.toString.call(x)&lt;/code&gt; as the catch-all.&lt;/p&gt;
&lt;h2&gt;
  
  
  Block B — this, prototypes &amp;amp; objects
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;9. How is &lt;code&gt;this&lt;/code&gt; determined?&lt;/strong&gt;&lt;br&gt;
By the call site, not where the function is defined. Four rules by priority: &lt;code&gt;new&lt;/code&gt;, explicit &lt;code&gt;call&lt;/code&gt;/&lt;code&gt;apply&lt;/code&gt;/&lt;code&gt;bind&lt;/code&gt;, implicit (&lt;code&gt;obj.method()&lt;/code&gt;), and default (&lt;code&gt;undefined&lt;/code&gt; in strict mode). Arrow functions ignore all of this and inherit &lt;code&gt;this&lt;/code&gt; lexically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dashboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tenant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;acme&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tenant&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;dashboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;          &lt;span class="c1"&gt;// 'acme'  (implicit: this = dashboard)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dashboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;                      &lt;span class="c1"&gt;// undefined — this lost (bare call = default binding)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;10. Arrow functions vs regular functions?&lt;/strong&gt;&lt;br&gt;
Arrows have no own &lt;code&gt;this&lt;/code&gt; (lexical), no &lt;code&gt;arguments&lt;/code&gt;, can't be &lt;code&gt;new&lt;/code&gt;ed, no &lt;code&gt;prototype&lt;/code&gt;. Use arrows for callbacks where you want the surrounding &lt;code&gt;this&lt;/code&gt;; regular functions for methods and constructors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11. What do call, apply, and bind do?&lt;/strong&gt;&lt;br&gt;
All set &lt;code&gt;this&lt;/code&gt; explicitly. &lt;code&gt;call(thisArg, a, b)&lt;/code&gt; invokes now with args listed; &lt;code&gt;apply(thisArg, [a, b])&lt;/code&gt; invokes now with args as an array; &lt;code&gt;bind&lt;/code&gt; returns a new function with &lt;code&gt;this&lt;/code&gt; (and leading args) permanently fixed — it doesn't call.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12. Explain prototypal inheritance and the prototype chain.&lt;/strong&gt;&lt;br&gt;
Every object has a hidden link (&lt;code&gt;[[Prototype]]&lt;/code&gt;) to another object. Property lookup walks this chain until found or it hits &lt;code&gt;null&lt;/code&gt;. Methods live on the prototype, shared across instances.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;instance --[[Prototype]]--&amp;gt; Campaign.prototype --&amp;gt; Object.prototype --&amp;gt; null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;13. Is class real inheritance or just sugar?&lt;/strong&gt;&lt;br&gt;
Syntactic sugar over prototypes. &lt;code&gt;class&lt;/code&gt; gives cleaner syntax for constructors, methods (on the prototype), &lt;code&gt;extends&lt;/code&gt;, and &lt;code&gt;super&lt;/code&gt; — but it's still prototype links underneath. It adds a few real things: methods are non-enumerable, and the body runs in strict mode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;14. Shallow vs deep copy — how do you copy an object?&lt;/strong&gt;&lt;br&gt;
Spread (&lt;code&gt;{...obj}&lt;/code&gt;) and &lt;code&gt;Object.assign&lt;/code&gt; are shallow — nested objects are still shared. For a deep copy use &lt;code&gt;structuredClone(obj)&lt;/code&gt; (handles cycles, Dates, Maps) — not &lt;code&gt;JSON.parse(JSON.stringify(...))&lt;/code&gt;, which drops functions, &lt;code&gt;undefined&lt;/code&gt;, and Dates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;15. What does Object.freeze do (and its limits)?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;Object.freeze(obj)&lt;/code&gt; makes own top-level properties non-writable/non-configurable — shallow immutability. Nested objects stay mutable (deep-freeze recursively). It's runtime enforcement; TS &lt;code&gt;readonly&lt;/code&gt; is compile-time only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;16. What are getters/setters and property descriptors?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;get&lt;/code&gt;/&lt;code&gt;set&lt;/code&gt; let a property run a function on read/write while looking like a field. &lt;code&gt;Object.defineProperty&lt;/code&gt; controls a property's descriptor — &lt;code&gt;writable&lt;/code&gt;, &lt;code&gt;enumerable&lt;/code&gt;, &lt;code&gt;configurable&lt;/code&gt;, or accessor functions.&lt;/p&gt;
&lt;h2&gt;
  
  
  Block C — async &amp;amp; the event loop
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;17. Explain the event loop.&lt;/strong&gt;&lt;br&gt;
JS runs on one thread. Sync code runs on the call stack. When the stack empties, the event loop drains the entire microtask queue (Promises), then runs one macrotask (setTimeout/I/O/UI), then drains microtasks again, and repeats.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;run sync (call stack) -&amp;gt; drain ALL microtasks -&amp;gt; run ONE macrotask -&amp;gt; drain ALL microtasks -&amp;gt; ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;18. What prints first: setTimeout(0) or Promise.then?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;Promise.then&lt;/code&gt;. A resolved promise's callback is a microtask; &lt;code&gt;setTimeout(0)&lt;/code&gt; is a macrotask. All microtasks run before the next macrotask.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;            &lt;span class="c1"&gt;// macrotask&lt;/span&gt;
&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c1"&gt;// microtask&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;D&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Output: A  D  C  B&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;19. Promises — states and error propagation?&lt;/strong&gt;&lt;br&gt;
A promise is pending, then settles once to fulfilled or rejected (immutable after). A rejection skips &lt;code&gt;.then&lt;/code&gt; handlers and jumps to the next &lt;code&gt;.catch&lt;/code&gt;. Returning a promise from &lt;code&gt;.then&lt;/code&gt; flattens. &lt;code&gt;.finally&lt;/code&gt; runs either way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;20. What does async/await desugar to, and how do you handle errors?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;async&lt;/code&gt; functions return a promise; &lt;code&gt;await&lt;/code&gt; pauses until a promise settles, then resumes. Errors are handled with &lt;code&gt;try/catch&lt;/code&gt; (a rejected awaited promise throws). An unawaited async call is a floating promise.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadKpis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/kpis?t=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kpi load failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                                     &lt;span class="c1"&gt;// graceful fallback&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;21. Promise.all vs allSettled vs race vs any?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;all&lt;/code&gt; — resolves when all succeed, rejects on first failure (fail-fast). &lt;code&gt;allSettled&lt;/code&gt; — waits for all, never rejects, returns each status. &lt;code&gt;race&lt;/code&gt; — settles as the first settles (success or failure). &lt;code&gt;any&lt;/code&gt; — resolves on first success, rejects only if all fail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;22. What are the most common async mistakes?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;await&lt;/code&gt; in a loop when calls are independent (serial instead of parallel), forgetting to await/return (floating), unhandled rejections, mixing callbacks with promises.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// SLOW: N serial round trips.&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;campaignIds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchStats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// FAST: fire all, await together.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;campaignIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fetchStats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;23. How do you convert a callback API to a promise?&lt;/strong&gt;&lt;br&gt;
Wrap it in &lt;code&gt;new Promise&lt;/code&gt;, calling &lt;code&gt;resolve&lt;/code&gt;/&lt;code&gt;reject&lt;/code&gt; inside the callback (or &lt;code&gt;util.promisify&lt;/code&gt; in Node).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;24. Implement debounce vs throttle — and when do you use each?&lt;/strong&gt;&lt;br&gt;
Debounce delays running until activity stops for N ms (search box). Throttle runs at most once per N ms during continuous activity (scroll/resize).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fetchResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Block D — functional patterns, memory &amp;amp; modern JS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;25. map / filter / reduce — and immutability in practice?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;map&lt;/code&gt; transforms each element, &lt;code&gt;filter&lt;/code&gt; selects a subset, &lt;code&gt;reduce&lt;/code&gt; folds a list into a single value. They return new arrays (immutable-friendly) — exactly what React state needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;byCampaign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;campaignId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??=&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;26. What are currying and function composition?&lt;/strong&gt;&lt;br&gt;
Currying turns &lt;code&gt;f(a, b, c)&lt;/code&gt; into &lt;code&gt;f(a)(b)(c)&lt;/code&gt; — fixing args one at a time. Composition chains small functions so one's output feeds the next (&lt;code&gt;compose(f, g)(x) = f(g(x))&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;27. What causes memory leaks in a browser SPA, and how do you prevent them?&lt;/strong&gt;&lt;br&gt;
Four causes: event listeners never removed, timers/intervals never cleared, closures that pin large objects, and detached DOM nodes still referenced. Clean up in your component's unmount/effect teardown.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onResize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onResize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;                          &lt;span class="c1"&gt;// WITHOUT this cleanup, every mount leaks&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onResize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;28. ESM vs CommonJS, and why does it matter for bundle size?&lt;/strong&gt;&lt;br&gt;
ESM (&lt;code&gt;import&lt;/code&gt;/&lt;code&gt;export&lt;/code&gt;) is static — the bundler can tree-shake unused code. CommonJS (&lt;code&gt;require&lt;/code&gt;) is dynamic and resists tree-shaking. ESM also enables dynamic &lt;code&gt;import()&lt;/code&gt; for code-splitting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Chart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./HeavyChart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;29. What are generators and iterators?&lt;/strong&gt;&lt;br&gt;
An iterator is any object with a &lt;code&gt;next()&lt;/code&gt; returning &lt;code&gt;{value, done}&lt;/code&gt;; the iterable protocol (&lt;code&gt;Symbol.iterator&lt;/code&gt;) is what &lt;code&gt;for...of&lt;/code&gt; and spread consume. A generator (&lt;code&gt;function*&lt;/code&gt; + &lt;code&gt;yield&lt;/code&gt;) pauses and resumes, producing values lazily. &lt;code&gt;async function*&lt;/code&gt; + &lt;code&gt;for await...of&lt;/code&gt; streams async data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;30. What is event delegation and why use it?&lt;/strong&gt;&lt;br&gt;
Attach one listener to a common ancestor and use &lt;code&gt;event.target&lt;/code&gt; to find which child fired — leveraging bubbling. Fewer listeners (less memory), and it handles elements added later automatically.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The through-line:&lt;/strong&gt; JavaScript's ergonomics hide real machinery. Predict output from the event loop, reason about &lt;code&gt;this&lt;/code&gt; from the call site, prevent leaks by cleaning up listeners/timers/references, and keep bundles lean with ESM + dynamic import. Answer each question with the engine behavior and the failure it prevents.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post was originally published on &lt;a href="https://prepstack.co.in/blog/javascript-senior-interview-questions-closures-event-loop-prototypes-async-deep-answers" rel="noopener noreferrer"&gt;PrepStack&lt;/a&gt;. The full original has all the code and senior-signal notes.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>interview</category>
      <category>frontend</category>
    </item>
    <item>
      <title>EF Core Interview Questions for Senior Developers in 2026 — Change Tracking, Performance, Concurrency &amp; Migrations</title>
      <dc:creator>kirandeepjassal-crypto</dc:creator>
      <pubDate>Wed, 21 Oct 2026 18:38:04 +0000</pubDate>
      <link>https://dev.to/kirandeepjassalcrypto/ef-core-interview-questions-for-senior-developers-in-2026-change-tracking-performance-1lii</link>
      <guid>https://dev.to/kirandeepjassalcrypto/ef-core-interview-questions-for-senior-developers-in-2026-change-tracking-performance-1lii</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Junior EF Core interviews ask "what is a DbContext." Senior interviews ask &lt;em&gt;why your dashboard fires 200 queries to render one page&lt;/em&gt;, &lt;em&gt;what happens when two users save the same row at once&lt;/em&gt;, and &lt;em&gt;why calling &lt;code&gt;Migrate()&lt;/code&gt; on startup took production down during a rolling deploy&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;EF Core makes the easy 80% trivial and hides the hard 20% — change tracking, query translation, concurrency, and schema evolution — right where production breaks. Seniority is knowing what SQL your LINQ actually becomes and what EF is doing on your behalf.&lt;/p&gt;

&lt;p&gt;This is 30 questions across &lt;strong&gt;change tracking &amp;amp; the DbContext, querying &amp;amp; performance, concurrency &amp;amp; transactions, and migrations &amp;amp; production&lt;/strong&gt;. Each has a short answer, a deep dive into the mechanism with code, and the senior signal the interviewer is listening for. Every example is from &lt;strong&gt;Mattrx&lt;/strong&gt; — a real multi-tenant marketing-analytics platform on &lt;strong&gt;.NET 9 / EF Core 9&lt;/strong&gt; over &lt;strong&gt;Azure SQL&lt;/strong&gt;, with &lt;code&gt;Campaigns&lt;/code&gt; (~4M rows) and &lt;code&gt;CampaignEvents&lt;/code&gt; (~1.2B rows), every query scoped by &lt;code&gt;TenantId&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block A — change tracking &amp;amp; the DbContext
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. What is change tracking, and how does SaveChanges know what to do?&lt;/strong&gt;&lt;br&gt;
The DbContext keeps a snapshot of every entity it loaded. On &lt;code&gt;SaveChanges&lt;/code&gt;, it diffs current values against that snapshot, computes each entity's state (Added / Modified / Deleted / Unchanged), and emits the minimal &lt;code&gt;INSERT&lt;/code&gt;/&lt;code&gt;UPDATE&lt;/code&gt;/&lt;code&gt;DELETE&lt;/code&gt; batch. Only changed columns go into the &lt;code&gt;UPDATE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What lifetime should DbContext have, and why not a singleton?&lt;/strong&gt;&lt;br&gt;
Scoped — one per request/unit of work. DbContext is not thread-safe and accumulates tracked entities, so a singleton corrupts state across concurrent requests and leaks memory as the tracker grows unbounded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. What does AsNoTracking do, and when do you use it?&lt;/strong&gt;&lt;br&gt;
It tells EF not to snapshot or track the results — no change-tracking overhead, less memory. Default for read-only queries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Campaigns&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsNoTracking&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TenantId&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;tenantId&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CampaignStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Active&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CampaignListItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UpdatedAt&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. How does EF decide INSERT vs UPDATE?&lt;/strong&gt;&lt;br&gt;
By tracked state, not by whether the entity "looks new." A detached entity (deserialized from an API) has no state until you attach it — then EF guesses from the key, which is the source of countless bugs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. What is the identity map (first-level cache)?&lt;/strong&gt;&lt;br&gt;
Within one DbContext, EF returns the same instance for the same key. Per-context consistency, not a cross-request cache — and why long-lived contexts drift from the DB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Tracking query returns stale data — why?&lt;/strong&gt;&lt;br&gt;
The identity map won't overwrite an already-tracked entity's values with fresh DB values by default. Use &lt;code&gt;AsNoTracking&lt;/code&gt;, a new context, or &lt;code&gt;Reload()&lt;/code&gt; for freshness.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. What's the danger of Update() on a whole entity?&lt;/strong&gt;&lt;br&gt;
It marks every property Modified, so EF writes all columns — overwriting fields you didn't intend to change and defeating concurrency. Prefer loading + mutating specific properties, or &lt;code&gt;ExecuteUpdate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. What is DbContext pooling and when does it help?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;AddDbContextPool&lt;/code&gt; reuses context instances (resetting state) to cut allocation/GC overhead at high throughput. Catch: you can't inject per-request state into the constructor.&lt;/p&gt;
&lt;h2&gt;
  
  
  Block B — querying &amp;amp; performance
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;9. IQueryable vs IEnumerable — where does the query run?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;IQueryable&lt;/code&gt; builds an expression tree EF translates to SQL and runs on the database. The moment you drop to &lt;code&gt;IEnumerable&lt;/code&gt;, the rest executes in memory on the app server. &lt;code&gt;Where&lt;/code&gt; on 1.2B rows in SQL vs in C# is the difference between 40ms and an outage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. What is the N+1 problem and how do you fix it?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// N+1: one query for campaigns, then one MORE per campaign for its count.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;campaigns&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Campaigns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TenantId&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;campaigns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CountAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CampaignId&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Fix: one server-side query that projects the aggregate.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Campaigns&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TenantId&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CampaignSummary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;11. Eager vs lazy vs explicit loading?&lt;/strong&gt;&lt;br&gt;
Eager (&lt;code&gt;Include&lt;/code&gt;) up front when you know you need it. Explicit (&lt;code&gt;.Entry(e).Collection(...).LoadAsync()&lt;/code&gt;) on demand, deliberately. Lazy (proxies) transparently on access — the #1 cause of accidental N+1; most teams disable it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12. Two Includes made the query huge — why?&lt;/strong&gt;&lt;br&gt;
Cartesian explosion. Multiple collection navigations produce a JOIN whose row count is the product of the collections. Fix with &lt;code&gt;AsSplitQuery()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;campaign&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Campaigns&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Segments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSplitQuery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefaultAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;13. Projection vs loading full entities?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;Select&lt;/code&gt; into a DTO fetches only those columns and skips tracking. Loading full entities pulls every column (including blobs) whether you use them or not. For reads, project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;14. What are compiled queries?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;EF.CompileAsyncQuery&lt;/code&gt; caches the LINQ→SQL translation so a hot query skips expression-tree compilation per call. EF already caches plans; reserve explicit compiled queries for genuinely hot paths you've measured.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;15. What is client-side evaluation and why is it dangerous?&lt;/strong&gt;&lt;br&gt;
When part of your LINQ can't translate to SQL, older EF silently ran it in memory after fetching all rows. EF Core 3.0+ throws instead (except the final projection) — treat that exception as the framework protecting you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;16. When do you drop to raw SQL, and how safely?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;FromSql&lt;/code&gt;/&lt;code&gt;ExecuteSql&lt;/code&gt; when LINQ can't express it. Use parameterized interpolation so EF parameterizes it — never string-concatenate user input (SQL injection).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SqlQuery&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DailyKpi&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;$@"SELECT ... FROM CampaignEvents&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                           WHERE TenantId = &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; AND EventDate &amp;gt;= &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;17. Streaming vs buffering results?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;ToListAsync&lt;/code&gt; buffers the whole set into memory. &lt;code&gt;AsAsyncEnumerable&lt;/code&gt; streams row by row — constant memory for large exports. Buffer small results; stream large ones.&lt;/p&gt;
&lt;h2&gt;
  
  
  Block C — concurrency &amp;amp; transactions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;18. How does optimistic concurrency work in EF Core?&lt;/strong&gt;&lt;br&gt;
Add a concurrency token (a SQL &lt;code&gt;rowversion&lt;/code&gt;). EF appends it to the &lt;code&gt;UPDATE&lt;/code&gt;'s &lt;code&gt;WHERE&lt;/code&gt;; if someone changed the row since you read it, 0 rows match and EF throws &lt;code&gt;DbUpdateConcurrencyException&lt;/code&gt; — a lost update becomes a detectable conflict.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Campaign&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Timestamp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;RowVersion&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;!;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// UPDATE Campaigns SET Name=@n WHERE Id=@id AND RowVersion=@original&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;19. How do you handle DbUpdateConcurrencyException?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbUpdateConcurrencyException&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Single&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;dbValues&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetDatabaseValuesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dbValues&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* row was deleted -&amp;gt; handle */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OriginalValues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dbValues&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// rebase, then retry&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pick a policy per entity: client wins, store wins, or merge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;20. How do transactions work in EF Core?&lt;/strong&gt;&lt;br&gt;
A single &lt;code&gt;SaveChanges&lt;/code&gt; is already atomic. For multiple saves or mixing EF with raw SQL as one unit, open an explicit &lt;code&gt;BeginTransactionAsync&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BeginTransactionAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Outbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CommitAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// both, or neither&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;21. Does EF Core support pessimistic locking?&lt;/strong&gt;&lt;br&gt;
Not natively — the model is optimistic. For &lt;code&gt;SELECT ... WITH (UPDLOCK, ROWLOCK)&lt;/code&gt; you drop to raw SQL inside a transaction. Default to optimistic unless contention is high.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;22. What is an execution strategy, and what's the transaction gotcha?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;EnableRetryOnFailure&lt;/code&gt; wraps operations in a retrying strategy for transient faults. A retrying strategy can't implicitly retry a user-initiated transaction — wrap that block in &lt;code&gt;strategy.ExecuteAsync(...)&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateExecutionStrategy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BeginTransactionAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ... multiple SaveChanges ...&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CommitAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;23. How do you do a bulk update without loading every row?&lt;/strong&gt;&lt;br&gt;
EF7+ &lt;code&gt;ExecuteUpdate&lt;/code&gt;/&lt;code&gt;ExecuteDelete&lt;/code&gt; run a set-based &lt;code&gt;UPDATE&lt;/code&gt;/&lt;code&gt;DELETE&lt;/code&gt; in SQL — no loading, no tracking, one round trip. They bypass the change tracker and don't run SaveChanges interceptors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Campaigns&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TenantId&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;tenantId&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CampaignStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Draft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteUpdateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CampaignStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Archived&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;24. How do you handle transient failures against Azure SQL?&lt;/strong&gt;&lt;br&gt;
Enable &lt;code&gt;EnableRetryOnFailure&lt;/code&gt; so EF retries transient errors with backoff. Pair with idempotent writes/optimistic concurrency so a retry after an ambiguous failure doesn't double-apply.&lt;/p&gt;
&lt;h2&gt;
  
  
  Block D — migrations, modeling &amp;amp; production
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;25. How do EF Core migrations work?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;dotnet ef migrations add&lt;/code&gt; diffs your model against the committed model snapshot (a C# file) and generates an &lt;code&gt;Up&lt;/code&gt;/&lt;code&gt;Down&lt;/code&gt; migration. &lt;code&gt;database update&lt;/code&gt; applies pending ones, recording each in &lt;code&gt;__EFMigrationsHistory&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;26. How should you apply migrations in production?&lt;/strong&gt;&lt;br&gt;
Not with &lt;code&gt;db.Database.Migrate()&lt;/code&gt; on startup — multiple instances race, it needs schema-owner permissions at runtime, and nothing is reviewed. Generate an idempotent SQL script in CI and apply it as a gated deploy step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet ef migrations script &lt;span class="nt"&gt;--idempotent&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; migrate.sql
-&amp;gt; review &lt;span class="k"&gt;in &lt;/span&gt;PR -&amp;gt; apply as an explicit, gated deploy step
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;27. Fluent API vs data annotations?&lt;/strong&gt;&lt;br&gt;
Annotations ([Required], [MaxLength]) are simple and co-located. Fluent API (&lt;code&gt;OnModelCreating&lt;/code&gt;) is more powerful (composite keys, relationships, filters, converters) and keeps mapping out of domain classes. Fluent wins where they conflict.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;28. What are owned types and value converters?&lt;/strong&gt;&lt;br&gt;
Owned types map a value object (Money, Address) into the owner's table without its own identity. Value converters translate a property between CLR and DB types (enum as string, encrypted column).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;29. What are global query filters and their pitfalls?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;HasQueryFilter&lt;/code&gt; applies a predicate to every query for an entity — perfect for multi-tenancy and soft-delete. Pitfalls: the context must be scoped, it doesn't apply to raw SQL, and you need &lt;code&gt;IgnoreQueryFilters()&lt;/code&gt; for admin/cross-tenant jobs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Campaign&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;HasQueryFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TenantId&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;_tenant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Campaigns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IgnoreQueryFilters&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(...).&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;30. What EF Core performance mistakes do you check for in production?&lt;/strong&gt;&lt;br&gt;
Missing &lt;code&gt;AsNoTracking&lt;/code&gt; on reads, N+1 from lazy loading, loading full entities instead of projecting, cartesian explosion from multiple &lt;code&gt;Include&lt;/code&gt;s, no pagination, client-side evaluation, &lt;code&gt;Update()&lt;/code&gt; writing all columns, and auto-migrate on startup. Verify with the generated SQL (&lt;code&gt;ToQueryString()&lt;/code&gt; / logging), not by trusting that it compiled.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The through-line:&lt;/strong&gt; EF Core is a leaky abstraction on purpose. Project reads into DTOs with &lt;code&gt;AsNoTracking&lt;/code&gt;, kill N+1 with one query, split multi-collection includes, make concurrency a &lt;code&gt;rowversion&lt;/code&gt; plus a resolution policy, wrap real units of work in explicit transactions with retries, and ship migrations as idempotent reviewed scripts. Answer each question with the generated SQL and the failure it prevents.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post was originally published on &lt;a href="https://prepstack.co.in/blog/ef-core-senior-interview-questions-tracking-performance-concurrency-migrations-deep-answers" rel="noopener noreferrer"&gt;PrepStack&lt;/a&gt;. The full original has all the code and senior-signal notes.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>interview</category>
      <category>database</category>
    </item>
    <item>
      <title>Microservices Interview Questions for Senior Developers in 2026 — Boundaries, Saga &amp; Consistency, Resilience &amp; Observability (Deep Answers)</title>
      <dc:creator>kirandeepjassal-crypto</dc:creator>
      <pubDate>Mon, 19 Oct 2026 16:31:27 +0000</pubDate>
      <link>https://dev.to/kirandeepjassalcrypto/microservices-interview-questions-for-senior-developers-in-2026-boundaries-saga-consistency-4beb</link>
      <guid>https://dev.to/kirandeepjassalcrypto/microservices-interview-questions-for-senior-developers-in-2026-boundaries-saga-consistency-4beb</guid>
      <description>&lt;p&gt;Junior microservices interviews ask "what is a microservice." Senior interviews ask &lt;em&gt;why your services share a database (so they're really one service that can't deploy independently)&lt;/em&gt;, &lt;em&gt;what happens when the payment call times out halfway through an order&lt;/em&gt;, and &lt;em&gt;how you debug a request that touched six services at 3am&lt;/em&gt;. Microservices trade in-process simplicity for distributed-systems hard problems — and seniority is knowing which problems you just bought and how to pay for them.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;30 questions&lt;/strong&gt; across four blocks: &lt;strong&gt;boundaries &amp;amp; decomposition, data &amp;amp; consistency, resilience &amp;amp; communication, and observability &amp;amp; production&lt;/strong&gt;. Every answer is a &lt;strong&gt;short answer&lt;/strong&gt; you could say in one breath, a &lt;strong&gt;deep dive&lt;/strong&gt; into the mechanism with code, and the &lt;strong&gt;senior signal&lt;/strong&gt; the interviewer is listening for. Every example is from &lt;strong&gt;Mattrx&lt;/strong&gt; — a multi-tenant marketing-analytics platform on .NET 9 whose services talk over Kafka, Azure Service Bus, and Event Grid.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lens for all 30
&lt;/h2&gt;

&lt;p&gt;A junior lists patterns; a senior reasons about &lt;strong&gt;what you traded for them&lt;/strong&gt;. "Should we use microservices?" gets "yes, they scale!" from a junior and "only when a module needs independent scaling/deploy/ownership — otherwise a modular monolith, because you're buying network failure, eventual consistency, and distributed debugging" from a senior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block A highlight — the distributed monolith
&lt;/h2&gt;

&lt;p&gt;The biggest failure mode is going distributed too early: services that &lt;em&gt;must&lt;/em&gt; deploy together, call each other in long synchronous chains, and share a DB — all the ops pain of microservices with none of the independence. The litmus test is one question: &lt;strong&gt;"can I deploy this service alone?"&lt;/strong&gt; If releasing these three services needs a specific order, they're one service wearing three uniforms. Draw boundaries by &lt;strong&gt;business capability / DDD bounded context&lt;/strong&gt;, not by technical layer (a layer split makes every feature cross every service).&lt;/p&gt;

&lt;h2&gt;
  
  
  Block B highlight — the outbox pattern
&lt;/h2&gt;

&lt;p&gt;The dual-write problem: you update your DB &lt;em&gt;and&lt;/em&gt; publish an event as two operations — a crash in between loses one. The outbox writes the event into an outbox table in the &lt;strong&gt;same transaction&lt;/strong&gt; as the state change; a relay publishes it afterward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BUG (dual write): a crash between these two loses the event.&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_bus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PublishAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CampaignPublished&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// if this fails, event is lost forever&lt;/span&gt;

&lt;span class="c1"&gt;// FIX (outbox): event + state commit atomically; a relay publishes from the outbox later.&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BeginTransactionAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Campaigns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;campaign&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Outbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OutboxMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"campaign.published"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CommitAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// atomic: state change AND event persist together&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And because delivery is &lt;strong&gt;at-least-once&lt;/strong&gt;, every consumer must be idempotent — dedup by a stable event id:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Consume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ConsumeContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ConversionTracked&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_dedup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryMarkProcessedAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                                    &lt;span class="c1"&gt;// already applied -&amp;gt; no-op&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_kpis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ApplyAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exactly-once &lt;em&gt;delivery&lt;/em&gt; is a myth; you get exactly-once &lt;em&gt;effect&lt;/em&gt; = at-least-once delivery + idempotent consumers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block C highlight — resilience (breaker + retry + timeout)
&lt;/h2&gt;

&lt;p&gt;One slow dependency makes its callers block, exhaust their pools, and fail — which fails &lt;em&gt;their&lt;/em&gt; callers: a cascade. Each resilience pattern caps one link.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddHttpClient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PaymentClient&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddResilienceHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"payment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;MaxRetryAttempts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BackoffType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DelayBackoffType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exponential&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UseJitter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddCircuitBreaker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;FailureRatio&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MinimumThroughput&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BreakDuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retry only transient/idempotent calls, with &lt;strong&gt;jitter + a budget&lt;/strong&gt; (fixed-interval retries synchronize into a retry storm that DDoSes the recovering service). Every call needs a &lt;strong&gt;timeout&lt;/strong&gt; (a hung dependency ties up threads forever) and &lt;strong&gt;bulkheads&lt;/strong&gt; isolate pools so one slow dependency can't sink the whole service. A &lt;strong&gt;dead-letter queue&lt;/strong&gt; parks poison messages instead of blocking the queue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block D highlight — distributed tracing
&lt;/h2&gt;

&lt;p&gt;A single request fans out across many services; without a trace id propagated through every hop, a failure is un-debuggable — six services' logs and no way to connect them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// One trace spans every hop; OTel propagates it via the W3C traceparent header.&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ActivitySource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GenerateReport"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;SetTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tenant.id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// downstream HTTP + Service Bus calls carry traceparent -&amp;gt; one correlated trace across services.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pair it with structured + centralized + trace-correlated logs and per-service RED metrics (Rate, Errors, Duration). And deploy schema changes with &lt;strong&gt;expand/contract&lt;/strong&gt;: add the new field (old + new both work) → migrate/backfill → drop the old once nothing uses it — so producers and consumers deploy in any order.&lt;/p&gt;

&lt;h2&gt;
  
  
  The through-line
&lt;/h2&gt;

&lt;p&gt;Microservices aren't "small services" — they're a bet that &lt;strong&gt;independent deployability is worth distributed-systems pain&lt;/strong&gt;. Everything follows: own your data (database-per-service), talk async where you can, accept eventual consistency and reconcile with sagas + the outbox, make every consumer idempotent, wrap every call in timeouts/breakers/retries-with-jitter, and make the whole thing observable with distributed tracing.&lt;/p&gt;

&lt;p&gt;The full guide has all 30 — each with the short answer, the deep dive with code, and the exact senior signal:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://prepstack.co.in/blog/microservices-senior-interview-questions-boundaries-saga-resilience-deep-answers" rel="noopener noreferrer"&gt;https://prepstack.co.in/blog/microservices-senior-interview-questions-boundaries-saga-resilience-deep-answers&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://prepstack.co.in/blog/microservices-senior-interview-questions-boundaries-saga-resilience-deep-answers" rel="noopener noreferrer"&gt;PrepStack&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>architecture</category>
      <category>interview</category>
      <category>webdev</category>
    </item>
    <item>
      <title>SQL Server Interview Questions for Senior Developers in 2026 — Execution Plans, Indexing, Locking &amp; Parameter Sniffing (Deep Answers)</title>
      <dc:creator>kirandeepjassal-crypto</dc:creator>
      <pubDate>Sat, 17 Oct 2026 20:16:54 +0000</pubDate>
      <link>https://dev.to/kirandeepjassalcrypto/sql-server-interview-questions-for-senior-developers-in-2026-execution-plans-indexing-locking--5gd7</link>
      <guid>https://dev.to/kirandeepjassalcrypto/sql-server-interview-questions-for-senior-developers-in-2026-execution-plans-indexing-locking--5gd7</guid>
      <description>&lt;p&gt;Junior SQL interviews ask "what is an index." Senior interviews ask &lt;em&gt;why the index you added is being ignored&lt;/em&gt;, &lt;em&gt;why a query that's fast for one tenant times out for another&lt;/em&gt;, and &lt;em&gt;why the deadlock only happens in production at 9am&lt;/em&gt;. SQL Server rewards people who can read a plan, reason about statistics and locks, and know when the database — not the C# — is the bottleneck.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;30 questions&lt;/strong&gt; across the four areas seniors actually get grilled on: &lt;strong&gt;indexing &amp;amp; tuning, execution plans &amp;amp; the optimizer, concurrency &amp;amp; locking, and performance &amp;amp; T-SQL&lt;/strong&gt;. Every answer is a &lt;strong&gt;short answer&lt;/strong&gt; you could say in one breath, a &lt;strong&gt;deep dive&lt;/strong&gt; into the mechanism with T-SQL, and the &lt;strong&gt;senior signal&lt;/strong&gt; the interviewer is listening for. Every example is from &lt;strong&gt;Mattrx&lt;/strong&gt; — a multi-tenant marketing-analytics SaaS on Azure SQL with &lt;code&gt;CampaignEvents&lt;/code&gt; at &lt;strong&gt;1.2 billion rows&lt;/strong&gt;, serving dashboards at ~3,200 req/sec.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lens for all 30
&lt;/h2&gt;

&lt;p&gt;A junior recites feature definitions; a senior reasons from the &lt;strong&gt;plan, the statistics, and the locks&lt;/strong&gt;. "Why is it slow?" gets "it does a scan" from a junior and "the predicate isn't SARGable so it scans, and the estimate-vs-actual skew says the stats are stale — here's the covering index and the RCSI change" from a senior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block A highlight — why your index isn't used (SARGability)
&lt;/h2&gt;

&lt;p&gt;Almost always because the predicate isn't &lt;strong&gt;SARGable&lt;/strong&gt; — a function/calculation on the indexed column, an implicit type conversion, or a leading wildcard — so SQL Server can't seek and falls back to a scan.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- NOT SARGable: function on the column -&amp;gt; scan.&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OccurredAt&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;day&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="nb"&gt;YEAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OccurredAt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- SARGable: range on the bare column -&amp;gt; seek.&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;OccurredAt&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;day&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;OccurredAt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;DATEADD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;day&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the companion fix — a &lt;strong&gt;covering index&lt;/strong&gt; that kills the key lookup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;NONCLUSTERED&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IX_Kpis_Cover&lt;/span&gt;
  &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CampaignDailyKpis&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TenantId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CampaignId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;Day&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;-- seek/range (equality before range, leftmost prefix)&lt;/span&gt;
  &lt;span class="n"&gt;INCLUDE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Impressions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Clicks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Conversions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;            &lt;span class="c1"&gt;-- covered -&amp;gt; no key lookup&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Block B highlight — parameter sniffing
&lt;/h2&gt;

&lt;p&gt;On first execution SQL Server "sniffs" the parameter values and compiles a plan for &lt;em&gt;them&lt;/em&gt;, then reuses it. If tenants have wildly different data distributions, the cached plan can be terrible for the next caller — a plan compiled for a tiny tenant (nested loops) reused for the biggest tanks p99.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- 1) OPTIMIZE FOR UNKNOWN: a stable, distribution-agnostic plan.&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;TenantId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;OPTION&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OPTIMIZE&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;UNKNOWN&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;-- 2) RECOMPILE: fresh plan every run for volatile ranges.&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="k"&gt;OPTION&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RECOMPILE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;-- 3) Query Store: force a known-good plan.&lt;/span&gt;
&lt;span class="c1"&gt;-- 4) Azure SQL compat 160: Parameter Sensitive Plan optimization (automatic).&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Diagnose it by the &lt;strong&gt;estimate-vs-actual row skew&lt;/strong&gt; in the actual plan — not the pretty picture. A big gap usually means stale statistics or a sniffing/SARGability problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block C highlight — RCSI vs NOLOCK
&lt;/h2&gt;

&lt;p&gt;With &lt;strong&gt;Read Committed Snapshot Isolation&lt;/strong&gt; on, readers get a consistent row-version snapshot instead of taking shared locks — so &lt;strong&gt;readers don't block writers and writers don't block readers&lt;/strong&gt;. The cost is extra tempdb for the version store.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="k"&gt;CURRENT&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;READ_COMMITTED_SNAPSHOT&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;-- readers use the version store, no S-locks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;WITH (NOLOCK)&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; a "make it faster" button — it's Read Uncommitted, reading &lt;strong&gt;dirty&lt;/strong&gt; data and able to &lt;strong&gt;miss or double-count rows&lt;/strong&gt; during page splits. Seniors reach for RCSI to get non-blocking reads &lt;em&gt;without&lt;/em&gt; the dirty-read hazards.&lt;/p&gt;

&lt;p&gt;And the lock-free queue pattern (&lt;code&gt;SKIP LOCKED&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- UPDLOCK reserves, READPAST skips rows other workers locked -&amp;gt; no double-dispatch, no blocking.&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;TOP&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OutboxMessages&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UPDLOCK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;READPAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ROWLOCK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Processing'&lt;/span&gt;
&lt;span class="k"&gt;OUTPUT&lt;/span&gt; &lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inserted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Payload&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Pending'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Block D highlight — keyset pagination and safe big writes
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;OFFSET n&lt;/code&gt; still &lt;strong&gt;reads and discards&lt;/strong&gt; the first &lt;code&gt;n&lt;/code&gt; rows, so page 10,000 gets linearly slower. &lt;strong&gt;Keyset pagination&lt;/strong&gt; seeks straight past the last row seen in constant time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- OFFSET: reads + throws away 200,000 rows. KEYSET: seeks directly.&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;TOP&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;EventId&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;lastEventId&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;EventId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a large DELETE/UPDATE is &lt;strong&gt;batched&lt;/strong&gt; so it never escalates to a table lock or bloats the log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;WHILE&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
  &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="n"&gt;TOP&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CampaignEvents&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;OccurredAt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;cutoff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="o"&gt;@@&lt;/span&gt;&lt;span class="n"&gt;ROWCOUNT&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt; &lt;span class="n"&gt;BREAK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The through-line
&lt;/h2&gt;

&lt;p&gt;Senior SQL Server is three instincts: &lt;strong&gt;make the query SARGable so the optimizer can seek; keep statistics fresh so it estimates right; and manage locks/isolation so reads and writes don't fight.&lt;/strong&gt; Nearly every "slow query" and "random deadlock" traces back to one of those. Read the plan, compare estimated to actual, change one thing at a time.&lt;/p&gt;

&lt;p&gt;The full guide has all 30 — covering indexes, key lookups, filtered indexes, cardinality estimation, Query Store, isolation levels, lock escalation, deadlock prevention, optimistic concurrency, columnstore, tempdb, and more — each with the short answer, the deep dive with T-SQL, and the exact senior signal:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://prepstack.co.in/blog/sql-server-senior-interview-questions-execution-plans-indexing-locking-deep-answers" rel="noopener noreferrer"&gt;https://prepstack.co.in/blog/sql-server-senior-interview-questions-execution-plans-indexing-locking-deep-answers&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://prepstack.co.in/blog/sql-server-senior-interview-questions-execution-plans-indexing-locking-deep-answers" rel="noopener noreferrer"&gt;PrepStack&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>sql</category>
      <category>database</category>
      <category>interview</category>
      <category>performance</category>
    </item>
    <item>
      <title>ASP.NET Core Interview Questions for Senior Developers in 2026 — Middleware Pipeline, DI Lifetimes, Kestrel &amp; Auth (Deep Answers)</title>
      <dc:creator>kirandeepjassal-crypto</dc:creator>
      <pubDate>Tue, 13 Oct 2026 05:48:51 +0000</pubDate>
      <link>https://dev.to/kirandeepjassalcrypto/aspnet-core-interview-questions-for-senior-developers-in-2026-middleware-pipeline-di-lifetimes-3mkf</link>
      <guid>https://dev.to/kirandeepjassalcrypto/aspnet-core-interview-questions-for-senior-developers-in-2026-middleware-pipeline-di-lifetimes-3mkf</guid>
      <description>&lt;p&gt;Junior ASP.NET Core interviews ask "what is middleware." Senior interviews ask &lt;em&gt;why your &lt;code&gt;UseAuthorization&lt;/code&gt; ran before routing and silently allowed an anonymous request through&lt;/em&gt;, or &lt;em&gt;why a singleton that took a &lt;code&gt;DbContext&lt;/code&gt; corrupted data across tenants&lt;/em&gt;. The framework is easy to use and easy to misuse in ways that only show up in production — under load, across tenants, at 3am.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;30 questions&lt;/strong&gt; across the four parts that actually separate seniors: the &lt;strong&gt;request pipeline&lt;/strong&gt;, &lt;strong&gt;DI &amp;amp; lifetimes&lt;/strong&gt;, &lt;strong&gt;hosting &amp;amp; performance&lt;/strong&gt;, and &lt;strong&gt;auth &amp;amp; APIs&lt;/strong&gt;. Every answer is a &lt;strong&gt;short answer&lt;/strong&gt; you could say in one breath, a &lt;strong&gt;deep dive&lt;/strong&gt; into the mechanism with code, and the &lt;strong&gt;senior signal&lt;/strong&gt; the interviewer is listening for. Every sample is from &lt;strong&gt;Mattrx&lt;/strong&gt; — a multi-tenant marketing-analytics SaaS on .NET 9 / ASP.NET Core, ~3,200 req/sec peak, Azure SQL + Redis, OAuth via Entra ID.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lens for all 30
&lt;/h2&gt;

&lt;p&gt;A junior describes a feature; a senior explains the &lt;strong&gt;ordering, lifetime, and failure mode&lt;/strong&gt;. "What is middleware?" gets "a request delegate chain" from a junior and "an ordered, unwinding pipeline where auth must sit between routing and endpoints, and a mis-order silently lets requests through" from a senior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block A highlight — the pipeline, and the #1 ordering bug
&lt;/h2&gt;

&lt;p&gt;Middleware is a chain of components, each of which can act on the request, call &lt;code&gt;next()&lt;/code&gt;, and act on the response as the chain unwinds. Order is everything: a component only sees what the components &lt;em&gt;before&lt;/em&gt; it let through.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request
  → [ ExceptionHandler ] → [ HTTPS ] → [ Routing ] → [ AuthN ] → [ AuthZ ] → [ Endpoint ]
  ← ───────────────────── response unwinds back up ───────────────────────── ┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The single most common pipeline bug: &lt;code&gt;UseAuthentication&lt;/code&gt;/&lt;code&gt;UseAuthorization&lt;/code&gt; must sit &lt;strong&gt;between &lt;code&gt;UseRouting&lt;/code&gt; and the endpoints&lt;/strong&gt;. Authorization needs to know &lt;em&gt;which endpoint&lt;/em&gt; matched to read its &lt;code&gt;[Authorize]&lt;/code&gt; metadata — which only exists after routing — and it must run &lt;em&gt;before&lt;/em&gt; the endpoint executes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseRouting&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;          &lt;span class="c1"&gt;// endpoint selected + its [Authorize] metadata attached&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthentication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// populate ctx.User&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    &lt;span class="c1"&gt;// enforce the selected endpoint's policy&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;      &lt;span class="c1"&gt;// BUG if this ran before UseAuthorization&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Block B highlight — the captive dependency bug
&lt;/h2&gt;

&lt;p&gt;A longer-lived service capturing a shorter-lived one — classically a &lt;strong&gt;singleton holding a scoped&lt;/strong&gt; service. The scoped service now lives forever, leaking state across requests/tenants and breaking thread-safety.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BUG: singleton CacheWarmer captures a scoped DbContext -&amp;gt; lives for the whole app.&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CacheWarmer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ctor takes MattrxDbContext (scoped)&lt;/span&gt;

&lt;span class="c1"&gt;// FIX: create a scope per unit of work.&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CacheWarmer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IServiceScopeFactory&lt;/span&gt; &lt;span class="n"&gt;scopes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;WarmAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scopes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateScope&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServiceProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MattrxDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// ...use db within this scope...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And why &lt;code&gt;DbContext&lt;/code&gt; is scoped: it's &lt;strong&gt;not thread-safe&lt;/strong&gt; and tracks entity state per unit of work. A singleton &lt;code&gt;DbContext&lt;/code&gt; across concurrent requests corrupts its change tracker ("A second operation was started on this context") and leaks data across tenants. The same scope-per-unit-of-work rule is how you use a &lt;code&gt;DbContext&lt;/code&gt; inside a &lt;code&gt;BackgroundService&lt;/code&gt; (which is itself a singleton).&lt;/p&gt;

&lt;h2&gt;
  
  
  Block C highlight — sync-over-async and thread-pool starvation
&lt;/h2&gt;

&lt;p&gt;Blocking a thread-pool thread (&lt;code&gt;.Result&lt;/code&gt;/&lt;code&gt;.Wait()&lt;/code&gt;) on async I/O ties up threads that can't serve other requests; under load the pool can't grow fast enough and latency explodes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// STARVATION: blocks a pool thread on I/O.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;kpis&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetKpisAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// CORRECT: keep the thread free.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;kpis&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetKpisAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plus: Kestrel behind a reverse proxy + &lt;code&gt;UseForwardedHeaders&lt;/code&gt;, config precedence with secrets in Key Vault, graceful &lt;code&gt;BackgroundService&lt;/code&gt; shutdown honoring the stopping token, caching tiers (in-process vs distributed Redis vs output caching), liveness vs readiness health checks, and the built-in rate limiter partitioned per tenant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block D highlight — multi-tenant isolation and JWT validation
&lt;/h2&gt;

&lt;p&gt;Derive the tenant from the &lt;strong&gt;authenticated token&lt;/strong&gt;, never from a query string, route, or header the client controls — then scope every query by it (with row-level security as a backstop).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// SAFE: tenant from the verified token, not from input.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tenantId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindFirstValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tenant_id"&lt;/span&gt;&lt;span class="p"&gt;)!;&lt;/span&gt;      &lt;span class="c1"&gt;// trusted&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Campaigns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TenantId&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// NEVER: var tenantId = Request.Query["tenantId"];    // client-controlled -&amp;gt; cross-tenant read&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A JWT bearer token is validated every request, statelessly: &lt;strong&gt;signature&lt;/strong&gt; (against the issuer's JWKS), &lt;strong&gt;issuer&lt;/strong&gt;, &lt;strong&gt;audience&lt;/strong&gt;, &lt;strong&gt;expiry&lt;/strong&gt;. The audience check is what stops a token minted for another API being replayed against yours (the confused-deputy guard). Also covered: roles vs claims vs policies vs resource-based auth, the CORS &lt;code&gt;AllowAnyOrigin&lt;/code&gt;+credentials mistake, when CSRF actually matters (cookie auth vs bearer tokens), and middleware vs MediatR pipeline behaviors for cross-cutting concerns.&lt;/p&gt;

&lt;h2&gt;
  
  
  The through-line
&lt;/h2&gt;

&lt;p&gt;Senior ASP.NET Core is four instincts: &lt;strong&gt;the pipeline is ordered and it unwinds; lifetimes are about shared state and thread-safety; the tenant and the user come from the token, never the request; and cross-cutting concerns live at the right layer.&lt;/strong&gt; Answer every question with the mechanism, the real failure it prevents, and the trade-off.&lt;/p&gt;

&lt;p&gt;The full guide has all 30 — each with the short answer, the deep dive with code, and the exact senior signal:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://prepstack.co.in/blog/aspnet-core-senior-interview-questions-middleware-di-kestrel-auth-deep-answers" rel="noopener noreferrer"&gt;https://prepstack.co.in/blog/aspnet-core-senior-interview-questions-middleware-di-kestrel-auth-deep-answers&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://prepstack.co.in/blog/aspnet-core-senior-interview-questions-middleware-di-kestrel-auth-deep-answers" rel="noopener noreferrer"&gt;PrepStack&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>aspnet</category>
      <category>interview</category>
      <category>webdev</category>
    </item>
    <item>
      <title>C# Interview Questions for Senior Developers in 2026 — async/await, GC &amp; Memory, the Type System, and LINQ (Deep Answers)</title>
      <dc:creator>kirandeepjassal-crypto</dc:creator>
      <pubDate>Wed, 07 Oct 2026 09:16:11 +0000</pubDate>
      <link>https://dev.to/kirandeepjassalcrypto/c-interview-questions-for-senior-developers-in-2026-asyncawait-gc-memory-the-type-system-5ddi</link>
      <guid>https://dev.to/kirandeepjassalcrypto/c-interview-questions-for-senior-developers-in-2026-asyncawait-gc-memory-the-type-system-5ddi</guid>
      <description>&lt;p&gt;Junior C# interviews test definitions — "what is a delegate," "value vs reference type." Senior interviews test &lt;em&gt;judgment&lt;/em&gt;: not &lt;em&gt;what&lt;/em&gt; async is, but &lt;em&gt;why&lt;/em&gt; your &lt;code&gt;.Result&lt;/code&gt; deadlocked in production; not &lt;em&gt;what&lt;/em&gt; a struct is, but &lt;em&gt;when&lt;/em&gt; copying one silently doubled your allocations.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;30 questions&lt;/strong&gt; across the four areas seniors actually get grilled on — &lt;strong&gt;async &amp;amp; concurrency, memory &amp;amp; GC, the type system, and LINQ &amp;amp; production patterns&lt;/strong&gt;. Every answer follows the same shape: a &lt;strong&gt;short answer&lt;/strong&gt; you could give in one breath, a &lt;strong&gt;deep dive&lt;/strong&gt; into the mechanism (with code), and the &lt;strong&gt;senior signal&lt;/strong&gt; the interviewer is listening for. Every snippet is from &lt;strong&gt;Mattrx&lt;/strong&gt; — a multi-tenant marketing-analytics SaaS on .NET 9 / ASP.NET Core / Azure SQL / Redis, with a 1.2B-row events table and a CQRS core.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lens for all 30
&lt;/h2&gt;

&lt;p&gt;A junior answers &lt;em&gt;what&lt;/em&gt;; a senior answers &lt;em&gt;why&lt;/em&gt;, &lt;em&gt;when-not-to&lt;/em&gt;, and &lt;em&gt;what it costs&lt;/em&gt;. "How does async work?" gets "it waits for the task" from a junior and "it suspends, frees the thread, and the continuation is scheduled — and here's how blocking on it deadlocks" from a senior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block A highlight — what actually happens when you &lt;code&gt;await&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;await&lt;/code&gt; is not "wait here." It's "suspend here, free the thread, and schedule the rest as a continuation." That's why an ASP.NET Core server handles thousands of concurrent requests on a small thread pool — threads aren't parked waiting on I/O.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AggregateAsync&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
      &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="n"&gt;suspend&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="n"&gt;returned&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="nf"&gt;pool&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;blocked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="err"&gt;▼&lt;/span&gt;
   &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="n"&gt;Azure&lt;/span&gt; &lt;span class="n"&gt;SQL&lt;/span&gt; &lt;span class="n"&gt;runs&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;aggregate&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
      &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="n"&gt;completes&lt;/span&gt;
      &lt;span class="err"&gt;▼&lt;/span&gt;
&lt;span class="n"&gt;continuation&lt;/span&gt; &lt;span class="n"&gt;resumes&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;pooled&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the classic deadlock: in a context-capturing host (classic ASP.NET, WPF), blocking the one context thread with &lt;code&gt;.Result&lt;/code&gt; while the continuation needs &lt;em&gt;that same thread&lt;/em&gt; to resume is a self-deadlock. The fix is "async all the way," never block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// DEADLOCK RISK: blocks the context thread&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;CampaignKpis&lt;/span&gt; &lt;span class="nf"&gt;GetKpis&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetKpisAsync&lt;/span&gt;&lt;span class="p"&gt;(...).&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// CORRECT — async all the way:&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CampaignKpis&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetKpisAsync&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetKpisAsync&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bounded concurrency is the other outage-preventer — never unbounded &lt;code&gt;Task.WhenAll&lt;/code&gt; over 10,000 tasks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Parallel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ForEachAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tenants&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ParallelOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;MaxDegreeOfParallelism&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tenant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;GenerateNightlyReportAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tenant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Block B highlight — GC, allocations, and the HttpClient trap
&lt;/h2&gt;

&lt;p&gt;.NET's GC is generational: most objects die young and are collected cheaply in &lt;strong&gt;gen 0&lt;/strong&gt;; survivors get promoted to gen 1, then gen 2 (whole-heap, expensive); objects &amp;gt;85KB go on the &lt;strong&gt;LOH&lt;/strong&gt;. The win on Mattrx — 2.1GB → 380MB working set — was mostly about &lt;em&gt;not promoting&lt;/em&gt; short-lived allocations to gen 2.&lt;/p&gt;

&lt;p&gt;And the senior HttpClient gotcha — know &lt;em&gt;both&lt;/em&gt; failure modes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BUG: socket exhaustion under load (TIME_WAIT)&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// A single static HttpClient fixes that but never picks up DNS changes.&lt;/span&gt;
&lt;span class="c1"&gt;// CORRECT: IHttpClientFactory — pooled, DNS-aware handlers.&lt;/span&gt;
&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"stripe"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;PostAsync&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boxing is the silent allocator — an enum boxed to &lt;code&gt;object&lt;/code&gt; per event is millions of gen-0 objects/sec at ingestion rate. &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt;/&lt;code&gt;Memory&amp;lt;T&amp;gt;&lt;/code&gt; give zero-allocation slicing (but &lt;code&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt; can't cross an &lt;code&gt;await&lt;/code&gt; — it's a &lt;code&gt;ref struct&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Block C highlight — deferred execution
&lt;/h2&gt;

&lt;p&gt;A LINQ query over &lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; doesn't run until you enumerate it; enumerating it &lt;em&gt;twice&lt;/em&gt; runs it &lt;em&gt;twice&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BUG: query executed TWICE — Count() enumerates, then the foreach enumerates again.&lt;/span&gt;
&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CampaignEvent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tenant&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// two DB round-trips&lt;/span&gt;
&lt;span class="c1"&gt;// FIX: materialize once.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tenant&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Block D highlight — the EF Core IQueryable trap
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;IQueryable&amp;lt;T&amp;gt;&lt;/code&gt; builds an expression tree EF translates to SQL (filtering runs in the database); &lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; runs LINQ in memory. Accidentally crossing the boundary is the difference between a WHERE clause and loading 1.2B rows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// GOOD: filter runs in Azure SQL&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CampaignEvents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TenantId&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;tenant&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OccurredAt&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// TRAP: ToList() first =&amp;gt; the Where now runs in memory over the ENTIRE table.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;bad&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CampaignEvents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TenantId&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;tenant&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plus the captive-dependency bug (a singleton capturing a scoped &lt;code&gt;DbContext&lt;/code&gt;), &lt;code&gt;ConcurrentDictionary.GetOrAdd&lt;/code&gt; running its factory twice under load (fix: &lt;code&gt;Lazy&amp;lt;T&amp;gt;&lt;/code&gt;), and why returning &lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; from a repository hands the caller control of &lt;em&gt;when and how many times&lt;/em&gt; your query executes — after the DbContext is disposed, or twice.&lt;/p&gt;

&lt;h2&gt;
  
  
  The through-line
&lt;/h2&gt;

&lt;p&gt;Senior C# is a handful of production truths: &lt;strong&gt;async suspends, it doesn't block; allocations become GC pressure; the type system is a compile-time aid, not a runtime guarantee; and the boundary between in-memory and in-database (or one thread and many) is where systems break.&lt;/strong&gt; Answer every question by naming the mechanism, the real failure it prevents, and the trade-off.&lt;/p&gt;

&lt;p&gt;The full guide has all 30 — each with the short answer, the deep dive with code, and the exact senior signal:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://prepstack.co.in/blog/csharp-senior-interview-questions-async-memory-linq-concurrency-deep-answers" rel="noopener noreferrer"&gt;https://prepstack.co.in/blog/csharp-senior-interview-questions-async-memory-linq-concurrency-deep-answers&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://prepstack.co.in/blog/csharp-senior-interview-questions-async-memory-linq-concurrency-deep-answers" rel="noopener noreferrer"&gt;PrepStack&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>interview</category>
      <category>programming</category>
    </item>
    <item>
      <title>Angular Interview Questions for Senior Developers in 2026 — Change Detection, RxJS, Signals &amp; Performance (Deep Answers)</title>
      <dc:creator>kirandeepjassal-crypto</dc:creator>
      <pubDate>Mon, 05 Oct 2026 11:31:25 +0000</pubDate>
      <link>https://dev.to/kirandeepjassalcrypto/angular-interview-questions-for-senior-developers-in-2026-change-detection-rxjs-signals--5fad</link>
      <guid>https://dev.to/kirandeepjassalcrypto/angular-interview-questions-for-senior-developers-in-2026-change-detection-rxjs-signals--5fad</guid>
      <description>&lt;p&gt;Junior Angular interviews ask "what is a component." Senior interviews ask &lt;em&gt;why your dashboard re-runs change detection thousands of times a second&lt;/em&gt;, &lt;em&gt;why a typeahead fires a request per keystroke and shows stale results&lt;/em&gt;, and &lt;em&gt;why that subscription leaks memory until the tab crawls&lt;/em&gt;. Angular is a big, opinionated framework, and seniority is knowing the machinery underneath — change detection, RxJS, the new signals model, and where performance goes to die.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;30 questions&lt;/strong&gt; across four blocks. Each answer is a &lt;strong&gt;short answer&lt;/strong&gt; you could say in one breath, a &lt;strong&gt;deep dive&lt;/strong&gt; into the mechanism (with code), and the &lt;strong&gt;senior signal&lt;/strong&gt; the interviewer is listening for. Examples use modern Angular (v17+: standalone, signals, the new control flow) and are grounded in &lt;strong&gt;Mattrx&lt;/strong&gt; — a real multi-tenant marketing-analytics platform whose internal admin console is built in Angular.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lens for all 30
&lt;/h2&gt;

&lt;p&gt;A junior uses the APIs; a senior understands &lt;strong&gt;change detection, the reactivity model, and RxJS semantics&lt;/strong&gt; — and designs to work &lt;em&gt;with&lt;/em&gt; them. "Why is the app janky?" gets a shrug from a junior and &lt;em&gt;"default CD is re-checking a 2,000-node tree on every mousemove — OnPush + signals cut it to the subtree that changed"&lt;/em&gt; from a senior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block B highlight — how change detection actually works
&lt;/h2&gt;

&lt;p&gt;Angular runs CD to sync model → DOM. &lt;strong&gt;Zone.js&lt;/strong&gt; monkey-patches async APIs (events, timers, XHR) so after any async task, Angular walks the component tree top-down and dirty-checks each binding.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async event (click / http / timer)
  -&amp;gt; zone.js notifies Angular
  -&amp;gt; CD walks the component tree top-down, checks each binding
  -&amp;gt; updates the DOM where a bound value changed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Default vs OnPush:&lt;/strong&gt; Default checks every component every run. &lt;strong&gt;OnPush&lt;/strong&gt; skips a component unless an &lt;code&gt;@Input&lt;/code&gt; &lt;em&gt;reference&lt;/em&gt; changed, an event fired inside it, or an &lt;code&gt;async&lt;/code&gt;-bound observable emitted. On big trees OnPush is the single biggest perf lever.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;campaign-list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;`@for (c of campaigns(); track c.id) { &amp;lt;campaign-row [campaign]="c" /&amp;gt; }&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;,
})
export class CampaignListComponent {
  campaigns = input.required&amp;lt;Campaign[]&amp;gt;();   // new reference -&amp;gt; this subtree is checked
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Senior signal: you default to OnPush, know it relies on immutable inputs, and can name the three triggers that still run it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block C highlight — the RxJS flattening operators
&lt;/h2&gt;

&lt;p&gt;The high-stakes RxJS question. They all map to an inner observable and flatten, differing in how they handle &lt;strong&gt;overlap&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;switchMap:  new value -&amp;gt; CANCEL previous, start new     (search/typeahead)
concatMap:  queue -&amp;gt; run one after another, in order    (ordered writes)
mergeMap:   run all concurrently                        (independent parallel)
exhaustMap: ignore new while one runs                   (dedupe rapid submits)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Typeahead: switchMap cancels the in-flight request when a new term arrives -&amp;gt; no stale results.&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;valueChanges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;debounceTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;distinctUntilChanged&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;term&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;term&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pick &lt;code&gt;switchMap&lt;/code&gt; for search, &lt;code&gt;exhaustMap&lt;/code&gt; for submit, &lt;code&gt;concatMap&lt;/code&gt; for ordered writes, &lt;code&gt;mergeMap&lt;/code&gt; for independent parallel work. &lt;strong&gt;Most "senior" candidates get tripped here.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Block C highlight — signals vs RxJS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Signals&lt;/strong&gt; are Angular's synchronous reactive primitive — a value you read as a function, with &lt;code&gt;computed()&lt;/code&gt; for derived values and &lt;code&gt;effect()&lt;/code&gt; for side effects. They power fine-grained, zoneless CD. RxJS stays for &lt;strong&gt;async streams/events&lt;/strong&gt;; signals are for &lt;strong&gt;synchronous state&lt;/strong&gt;. Bridge with &lt;code&gt;toSignal&lt;/code&gt; / &lt;code&gt;toObservable&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;double&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;          &lt;span class="c1"&gt;// recomputes only when count changes&lt;/span&gt;
&lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                       &lt;span class="c1"&gt;// triggers dependents precisely&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And preventing leaks — prefer the async pipe or &lt;code&gt;takeUntilDestroyed()&lt;/code&gt; over manual &lt;code&gt;ngOnDestroy&lt;/code&gt; bookkeeping:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pollKpis&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;takeUntilDestroyed&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kpis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The through-line
&lt;/h2&gt;

&lt;p&gt;Angular is fast and maintainable when you cooperate with change detection (OnPush, immutability, signals), pick the right RxJS operator by its overlap semantics, and tear down subscriptions (async pipe / &lt;code&gt;takeUntilDestroyed&lt;/code&gt;). Fight it and you get jank and leaks. Answer each question with the mechanism &lt;strong&gt;and the failure it prevents&lt;/strong&gt;, and you sound like someone who has shipped and profiled a real Angular app.&lt;/p&gt;

&lt;p&gt;The full guide has all 30 — components &amp;amp; DI, change detection &amp;amp; performance, RxJS &amp;amp; state, and routing/forms/testing/production — each with the short answer, the deep dive with code, and the exact senior signal:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://prepstack.co.in/blog/angular-senior-interview-questions-change-detection-rxjs-signals-performance-deep-answers" rel="noopener noreferrer"&gt;https://prepstack.co.in/blog/angular-senior-interview-questions-change-detection-rxjs-signals-performance-deep-answers&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://prepstack.co.in/blog/angular-senior-interview-questions-change-detection-rxjs-signals-performance-deep-answers" rel="noopener noreferrer"&gt;PrepStack&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>rxjs</category>
      <category>interview</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Angular Performance Optimization in 2026 — OnPush, trackBy, Lazy Loading, Signals, Standalone (Real Code, Production Metrics)</title>
      <dc:creator>kirandeepjassal-crypto</dc:creator>
      <pubDate>Wed, 30 Sep 2026 17:34:20 +0000</pubDate>
      <link>https://dev.to/kirandeepjassalcrypto/angular-performance-optimization-in-2026-onpush-trackby-lazy-loading-signals-standalone-real-3f8m</link>
      <guid>https://dev.to/kirandeepjassalcrypto/angular-performance-optimization-in-2026-onpush-trackby-lazy-loading-signals-standalone-real-3f8m</guid>
      <description>&lt;p&gt;Angular apps don't go slow because Angular is slow. They go slow because the defaults — &lt;code&gt;Default&lt;/code&gt; change detection, NgModules with eager imports, no &lt;code&gt;trackBy&lt;/code&gt;, BehaviorSubject everywhere, no lazy loading — were designed for a world where bundle size and per-keystroke render cost weren't the user-facing scoreboard. In 2026 they are: Core Web Vitals (LCP, INP) are part of the Google ranking signal &lt;em&gt;and&lt;/em&gt; the conversion funnel.&lt;/p&gt;

&lt;p&gt;This is the production playbook for Angular 19+. Five techniques compose into the biggest wins, each with before/after code and real metrics from &lt;strong&gt;Mattrx&lt;/strong&gt; — a multi-tenant marketing-analytics SaaS (Angular 16 → 19, 540+ components, 22k LOC, 110k MAU).&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR — the five, ranked by impact
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Technique&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;th&gt;Win&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Lazy loading&lt;/strong&gt; (routes + &lt;code&gt;@defer&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Initial JS 1.2 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;290 KB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;LCP −67%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;OnPush&lt;/strong&gt; change detection&lt;/td&gt;
&lt;td&gt;60 CD cycles/sec&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;3/sec&lt;/strong&gt; on dashboard&lt;/td&gt;
&lt;td&gt;INP −78%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Signals&lt;/strong&gt; (replace BehaviorSubject)&lt;/td&gt;
&lt;td&gt;manual &lt;code&gt;markForCheck&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;auto-react on read&lt;/td&gt;
&lt;td&gt;fewer bugs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Standalone components&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;NgModule barrels&lt;/td&gt;
&lt;td&gt;direct imports, tree-shake&lt;/td&gt;
&lt;td&gt;bundle −18%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;trackBy&lt;/code&gt; / &lt;code&gt;track&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4,000 nodes recreated&lt;/td&gt;
&lt;td&gt;only changed rows&lt;/td&gt;
&lt;td&gt;filter 280ms → 35ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Aggregate (Angular 16 → 19 + the 5 techniques, 4 weeks, no new features):&lt;/strong&gt; LCP 4.6s → &lt;strong&gt;1.5s&lt;/strong&gt;, INP 420ms → &lt;strong&gt;80ms&lt;/strong&gt;, initial JS 1.2 MB → &lt;strong&gt;290 KB&lt;/strong&gt;, CrUX "Good" CWV 38% → &lt;strong&gt;91%&lt;/strong&gt;, trial signup conversion &lt;strong&gt;+12%&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model you need: change detection
&lt;/h2&gt;

&lt;p&gt;Every time Zone.js patches an async API (click, XHR, &lt;code&gt;setTimeout&lt;/code&gt;), Angular schedules a CD pass and walks the tree top-down. &lt;strong&gt;Default CD re-checks every binding on every component on every pass&lt;/strong&gt; — even if nothing changed. A &lt;code&gt;setInterval(fn, 100)&lt;/code&gt; triggers a full-app CD pass every 100ms. &lt;code&gt;OnPush&lt;/code&gt; prunes the tree: a component is checked only when an &lt;code&gt;@Input&lt;/code&gt; reference changes, an event fires in it, an &lt;code&gt;async&lt;/code&gt; pipe emits, a signal it reads changes, or &lt;code&gt;markForCheck()&lt;/code&gt; is called.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Lazy loading — the biggest LCP win
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/login.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LoginComponent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/dashboard.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DashboardComponent&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;canMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;authGuard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reports&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/reports/reports.routes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REPORTS_ROUTES&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;canMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;authGuard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add background prefetch so subsequent navigation is instant too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;provideRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;withPreloading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PreloadAllModules&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then &lt;code&gt;@defer&lt;/code&gt; for anything heavy that isn't above-the-fold:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@defer (on viewport) {
  &lt;span class="nt"&gt;&amp;lt;mx-revenue-chart&lt;/span&gt; &lt;span class="na"&gt;[data]=&lt;/span&gt;&lt;span class="s"&gt;"revenue()"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
} @placeholder {
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"chart-skeleton h-64"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
} @loading (minimum 200ms) {
  &lt;span class="nt"&gt;&amp;lt;mx-spinner&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
} @error {
  &lt;span class="nt"&gt;&amp;lt;mx-chart-load-error&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@defer&lt;/code&gt; downloads the component &lt;strong&gt;and its transitive imports&lt;/strong&gt; as a separate chunk automatically — no webpack config. Triggers: &lt;code&gt;on idle&lt;/code&gt;, &lt;code&gt;on viewport&lt;/code&gt;, &lt;code&gt;on interaction&lt;/code&gt;, &lt;code&gt;on hover&lt;/code&gt;, &lt;code&gt;on timer(2s)&lt;/code&gt;, &lt;code&gt;when condition&lt;/code&gt;. &lt;strong&gt;Result: initial bundle 1.2 MB → 290 KB, LCP 4.6s → 1.5s.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. OnPush — the biggest CPU win
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mx-kpi-card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;`...&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;,
})
export class KpiCardComponent {
  @Input() label!: string;
  @Input() value!: number;
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Mattrx dashboard did ~&lt;strong&gt;13,000 binding evaluations/sec at idle&lt;/strong&gt;. Blanket OnPush on leaf components: &lt;strong&gt;540/sec&lt;/strong&gt;. The contract: never mutate input objects in place — create new references (&lt;code&gt;this.user = {...this.user, name}&lt;/code&gt;), or use Signals to enforce it structurally. Convert leaf components first (cards, rows, badges) — highest fan-out.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Signals — replace BehaviorSubject for state
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KpiService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;kpis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Kpis&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;revenuePerCampaign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;kpis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;campaigns&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;revenue&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;campaigns&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Kpis&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;`/api/kpis?u=&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{id}&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;).subscribe(v =&amp;gt; this.kpis.set(v)); }
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reading &lt;code&gt;kpis()&lt;/code&gt; in a template auto-subscribes the component; &lt;code&gt;kpis.set(...)&lt;/code&gt; marks only readers for check. No async pipe, no &lt;code&gt;markForCheck&lt;/code&gt;, no &lt;code&gt;takeUntilDestroyed&lt;/code&gt;. Use Signals for component/service state; keep RxJS for genuine async pipelines (HTTP, WebSocket, debounced search) and bridge with &lt;code&gt;toSignal&lt;/code&gt; / &lt;code&gt;toObservable&lt;/code&gt;. &lt;strong&gt;/inbox: re-renders per WebSocket message 23 → 2, 62 &lt;code&gt;takeUntilDestroyed&lt;/code&gt; removed.&lt;/strong&gt; Once everything reads signals, you're on the path to zoneless (−28 KB bundle).&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Standalone components — tree-shaking + lazy loading
&lt;/h2&gt;

&lt;p&gt;Standalone (default in Angular 19) drops the NgModule ceremony and lets the bundler see the exact import graph — no barrel of unrelated junk. Run the schematic in chunks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng generate @angular/core:standalone
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Mattrx: 540 components in ~3 days, ~8% needed manual tweaks (mostly &lt;code&gt;forwardRef&lt;/code&gt; cycles). &lt;strong&gt;Bundle −18% on top of lazy; compile time 42s → 28s.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. trackBy / &lt;a class="mentioned-user" href="https://dev.to/for"&gt;@for&lt;/a&gt; track — the afternoon fix
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@for (campaign of filteredCampaigns(); track campaign.id) {
  &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;{{ campaign.name }}&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;{{ campaign.spend | currency }}&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
} @empty {
  &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;colspan=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;No campaigns match.&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without a stable &lt;code&gt;track&lt;/code&gt;, filtering a 4,000-row table (new array of references) destroys and recreates &lt;strong&gt;all 4,000 DOM nodes&lt;/strong&gt; — and silently unchecks checkboxes. With &lt;code&gt;track campaign.id&lt;/code&gt;: only changed rows. &lt;strong&gt;Use a stable id, never &lt;code&gt;$index&lt;/code&gt; for dynamic lists.&lt;/strong&gt; Filter latency &lt;strong&gt;280ms → 35ms&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: block control flow
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@if&lt;/code&gt; / &lt;code&gt;@for&lt;/code&gt; / &lt;code&gt;@switch&lt;/code&gt; (Angular 17+) compile smaller and faster than &lt;code&gt;*ngIf&lt;/code&gt; / &lt;code&gt;*ngFor&lt;/code&gt;, support &lt;code&gt;@else if&lt;/code&gt; and &lt;code&gt;@empty&lt;/code&gt;. Use for all new code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The right mental model
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Do less work, and do it later.&lt;/strong&gt; Lazy loading = do it later. OnPush = do less. &lt;code&gt;track&lt;/code&gt; = don't recreate what didn't change. Signals = do less, more precisely. Standalone = ship only what you use.&lt;/p&gt;

&lt;p&gt;Three habits: OnPush + standalone on every new component by default; lazy-load before you optimize; profile before you tune (Chrome Performance, &lt;code&gt;ng build --stats-json&lt;/code&gt;, Lighthouse).&lt;/p&gt;

&lt;p&gt;The full guide has every before/after, the Default-vs-OnPush tree-walk diagrams, the bundle-split diagram, the full &lt;code&gt;@defer&lt;/code&gt; trigger list, the Signals interop table, and the step-by-step diagnostic checklist for inheriting a slow app:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://prepstack.co.in/blog/angular-performance-optimization-guide-onpush-trackby-lazy-loading-signals-standalone-components" rel="noopener noreferrer"&gt;https://prepstack.co.in/blog/angular-performance-optimization-guide-onpush-trackby-lazy-loading-signals-standalone-components&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://prepstack.co.in/blog/angular-performance-optimization-guide-onpush-trackby-lazy-loading-signals-standalone-components" rel="noopener noreferrer"&gt;PrepStack&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>performance</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Angular Micro Frontends in 2026 — Webpack Module Federation vs Native Federation, Independent Deployments (Real Project, Production Metrics)</title>
      <dc:creator>kirandeepjassal-crypto</dc:creator>
      <pubDate>Mon, 28 Sep 2026 18:06:26 +0000</pubDate>
      <link>https://dev.to/kirandeepjassalcrypto/angular-micro-frontends-in-2026-webpack-module-federation-vs-native-federation-independent-58h5</link>
      <guid>https://dev.to/kirandeepjassalcrypto/angular-micro-frontends-in-2026-webpack-module-federation-vs-native-federation-independent-58h5</guid>
      <description>&lt;p&gt;Micro frontends sound like an architecture pattern. They're actually a &lt;strong&gt;deployment&lt;/strong&gt; pattern that happens to have UI consequences. The question they answer isn't "how do we structure code?" — it's &lt;em&gt;"can team A ship without waiting for team B, even though both teams' code runs in the same browser tab?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The wrong reason to adopt them: "our app is big." (Big apps want an Nx monorepo with feature libraries.) The &lt;strong&gt;right&lt;/strong&gt; reason: independent deployments, different release cadences, separate teams that don't want to coordinate every push to production.&lt;/p&gt;

&lt;p&gt;This is the production playbook, built on the same real app throughout: &lt;strong&gt;Mattrx&lt;/strong&gt;, a multi-tenant marketing-analytics SaaS on Angular 19, where the partner-widgets team carved out into a separate remote in early 2026. Real numbers from that split are throughout.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one idea
&lt;/h2&gt;

&lt;p&gt;Independent deployment is the whole point. The shell's HTML never re-bundles the remote — it fetches it fresh at runtime (or from cache), evaluates it in place, and reuses the singleton shared deps. Update the remote on its CDN → the next navigation picks it up. &lt;strong&gt;The shell does not redeploy when the remote ships.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Three concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Host&lt;/strong&gt; (shell) — loads first. Owns routing, auth, layout, in-host features. Knows the &lt;em&gt;URLs&lt;/em&gt; of its remotes, not their &lt;em&gt;code&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remote&lt;/strong&gt; — a separately-built, separately-deployed Angular sub-app that exposes lazy-loadable components/routes via a manifest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contract&lt;/strong&gt; — the named exports each remote exposes. The host imports them &lt;em&gt;by name&lt;/em&gt;; the remote promises to keep them stable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Two paths: Webpack MF vs Native Federation
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Webpack MF&lt;/th&gt;
&lt;th&gt;Native Federation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Basis&lt;/td&gt;
&lt;td&gt;Webpack 5 ModuleFederationPlugin&lt;/td&gt;
&lt;td&gt;Import Maps + ESM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build&lt;/td&gt;
&lt;td&gt;webpack (slower)&lt;/td&gt;
&lt;td&gt;esbuild (faster)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Config&lt;/td&gt;
&lt;td&gt;custom webpack&lt;/td&gt;
&lt;td&gt;default Angular builder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New Angular 19 project&lt;/td&gt;
&lt;td&gt;only with webpack expertise&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Recommended&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Already on webpack&lt;/td&gt;
&lt;td&gt;stay&lt;/td&gt;
&lt;td&gt;migrate later if convenient&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For Mattrx we chose &lt;strong&gt;Native Federation&lt;/strong&gt; for the two new remotes. Honest reason: it didn't require swapping our build system back to webpack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native Federation — the modern setup
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; @angular-architects/native-federation
ng add @angular-architects/native-federation &lt;span class="nt"&gt;--project&lt;/span&gt; shell &lt;span class="nt"&gt;--type&lt;/span&gt; host &lt;span class="nt"&gt;--port&lt;/span&gt; 4200
ng add @angular-architects/native-federation &lt;span class="nt"&gt;--project&lt;/span&gt; partner-widgets &lt;span class="nt"&gt;--type&lt;/span&gt; remote &lt;span class="nt"&gt;--port&lt;/span&gt; 4201
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shell points at remotes via a small JSON manifest (&lt;code&gt;.json&lt;/code&gt;, not &lt;code&gt;.js&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="c1"&gt;// apps/shell/src/assets/manifest.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"partner-widgets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://partners.mattrx.io/remoteEntry.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"labs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s2"&gt;"https://labs.mattrx.io/remoteEntry.json"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lazy route pulls the remote:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loadRemoteModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular-architects/native-federation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;APP_ROUTES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@mattrx/features/dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DASHBOARD_ROUTES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;partners&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="na"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;partner-widgets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PARTNER_ROUTES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The remote declares what it exposes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// apps/partner-widgets/federation.config.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withNativeFederation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;partner-widgets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;exposes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                 &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./apps/partner-widgets/src/app/partner.routes.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./PartnerCampaignsWidget&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./apps/partner-widgets/src/app/widgets/partner-campaigns.component.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;shareAll&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;singleton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;strictVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;requiredVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The day-2 reality (where the real engineering lives)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Immutable chunks, mutable manifest.&lt;/strong&gt; &lt;code&gt;remoteEntry.json&lt;/code&gt; changes every deploy → &lt;code&gt;Cache-Control: no-cache&lt;/code&gt;. The content-hashed chunks it references → cache forever. Get this wrong and a user loads &lt;em&gt;yesterday's&lt;/em&gt; manifest pointing at &lt;em&gt;today's&lt;/em&gt; missing chunks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Atomic deploys.&lt;/strong&gt; Upload chunks first, verify they return 200 from the CDN, &lt;em&gt;then&lt;/em&gt; flip the manifest pointer. If the manifest goes live before the chunks exist, anyone loading in that window crashes. We learned this the hard way — two broken minutes in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shared dependency version drift — the #1 source of pain.&lt;/strong&gt; If the shell is on &lt;code&gt;@angular/core@19.1.3&lt;/code&gt; and the remote was built against &lt;code&gt;19.0.7&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;singleton: true, strictVersion: true&lt;/code&gt; — boot-time error. Loud, deterministic, right. &lt;strong&gt;Use this for Angular packages.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;strictVersion: false&lt;/code&gt; — uses whichever loaded first. Silent breakage if APIs drift. OK only for a backwards-compatible design system.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;singleton: false&lt;/code&gt; — two Angulars. Don't.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the shell bumps an Angular minor, every remote bumps the same week — a "version-bump-only" PR per remote.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The exposes contract is a SemVer surface.&lt;/strong&gt; The host imports &lt;code&gt;'./PartnerCampaignsWidget'&lt;/code&gt; by name — that string is a public contract. Add freely, coordinate on signature changes, deprecate-for-one-release before removing. Keep a literal &lt;code&gt;EXPOSES.md&lt;/code&gt; per remote. Contract-test it in CI against the remote's staging URL, on every shell PR &lt;em&gt;and&lt;/em&gt; every remote PR.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rollback is flipping the manifest back:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;s3://mattrx-partners/remoteEntry.PREVIOUS.json s3://mattrx-partners/remoteEntry.json
aws cloudfront create-invalidation &lt;span class="nt"&gt;--distribution-id&lt;/span&gt; ABC &lt;span class="nt"&gt;--paths&lt;/span&gt; &lt;span class="s2"&gt;"/remoteEntry.json"&lt;/span&gt;
&lt;span class="c"&gt;# Live within ~30s. No build, no redeploy.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The production numbers (after carving out 2 remotes)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Partner team deploys/week&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;15–40&lt;/strong&gt; (3–8/day)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time to ship a partner hotfix&lt;/td&gt;
&lt;td&gt;25 min&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4 min&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-team coordination tickets/sprint&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prod incidents from cross-team merges/mo&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shell bundle (gzipped)&lt;/td&gt;
&lt;td&gt;290 KB&lt;/td&gt;
&lt;td&gt;290 KB (unchanged)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cold-start LCP (first remote hit)&lt;/td&gt;
&lt;td&gt;1.5s&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;1.7s&lt;/strong&gt; (+200ms — honest cost)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warm-start LCP (cached remote)&lt;/td&gt;
&lt;td&gt;1.5s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.4s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rollback on a remote regression&lt;/td&gt;
&lt;td&gt;25 min&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;45 seconds&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The LCP cost is real and we own it. Idle-prefetch the manifest after the shell loads and cold-start drops back to ~+40ms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;provideAppInitializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;requestIdleCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;r&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;prefetchRemote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;partner-widgets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When NOT to use micro frontends
&lt;/h2&gt;

&lt;p&gt;The most-skipped section of every MFE article. &lt;strong&gt;Most teams shouldn't.&lt;/strong&gt; Don't reach for MFEs if you're under ~25 frontend engineers in 1–2 teams, if you want smaller bundles (that's lazy loading), if you want faster CI (&lt;code&gt;nx affected&lt;/code&gt; is cheaper), or if your teams ship together anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do&lt;/strong&gt; consider them if a team ships to a different surface (partner CDN, extension), needs a conflicting deploy cadence, embeds the same code in third-party hosts, or is an acquired team merging in without a rewrite. For Mattrx, exactly one of those was true — so we carved out one remote, not ten.&lt;/p&gt;

&lt;h2&gt;
  
  
  The right mental model
&lt;/h2&gt;

&lt;p&gt;Micro frontends are &lt;strong&gt;an operational tool dressed in architecture clothes.&lt;/strong&gt; The architecture exists &lt;em&gt;so that&lt;/em&gt; the deployment property (independent ship) becomes possible. Without the deployment property, the architecture is overhead with no upside.&lt;/p&gt;

&lt;p&gt;Three habits: adopt one remote at a time for one reason at a time; treat the &lt;code&gt;exposes&lt;/code&gt; contract as a SemVer surface (document + test in CI); coordinate the boring stuff (Angular minor bumps, design-system versions, CDN caching).&lt;/p&gt;

&lt;p&gt;The full guide has the complete Webpack MF setup too, the request-flow and deploy-flow diagrams, the embeddable-widget use case, the 8-week adoption path, and the honest "what we'd do again / what we'd skip":&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://prepstack.co.in/blog/angular-micro-frontends-module-federation-webpack-native-federation-independent-deployments-guide" rel="noopener noreferrer"&gt;https://prepstack.co.in/blog/angular-micro-frontends-module-federation-webpack-native-federation-independent-deployments-guide&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://prepstack.co.in/blog/angular-micro-frontends-module-federation-webpack-native-federation-independent-deployments-guide" rel="noopener noreferrer"&gt;PrepStack&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>architecture</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Angular Signals vs RxJS in 2026 — When to Use Each, Performance Benchmarks, and the Interop Pattern (Real Code)</title>
      <dc:creator>kirandeepjassal-crypto</dc:creator>
      <pubDate>Sat, 26 Sep 2026 17:51:32 +0000</pubDate>
      <link>https://dev.to/kirandeepjassalcrypto/angular-signals-vs-rxjs-in-2026-when-to-use-each-performance-benchmarks-and-the-interop-pattern-28b0</link>
      <guid>https://dev.to/kirandeepjassalcrypto/angular-signals-vs-rxjs-in-2026-when-to-use-each-performance-benchmarks-and-the-interop-pattern-28b0</guid>
      <description>&lt;p&gt;"Should I use Signals or RxJS for this?" is the most-asked question in modern Angular code review. The bad answer — &lt;em&gt;"use Signals everywhere, RxJS is legacy"&lt;/em&gt; — produces fragile WebSocket handling and re-invented &lt;code&gt;switchMap&lt;/code&gt;. The other bad answer — &lt;em&gt;"stick with RxJS, Signals are toys"&lt;/em&gt; — produces 30 lines of &lt;code&gt;BehaviorSubject&lt;/code&gt; + &lt;code&gt;takeUntilDestroyed&lt;/code&gt; to track which tab is active.&lt;/p&gt;

&lt;p&gt;The right answer is mechanical, not philosophical: &lt;strong&gt;Signals are pull-based, synchronous, fine-grained reactive values; RxJS is push-based, asynchronous, time-aware event composition.&lt;/strong&gt; Each is excellent at exactly one half of the problem. Real code, benchmarks, and production numbers from migrating &lt;strong&gt;Mattrx&lt;/strong&gt; — a multi-tenant marketing-analytics SaaS (540 components, 22k LOC, 110k MAU).&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model (the one chart you need)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                        SIGNALS                  RxJS
Direction              PULL (read latest)       PUSH (subscribe, get next)
Time                   SYNCHRONOUS              ASYNCHRONOUS
Granularity            Per-value, fine-grained  Per-stream, coarse-grained
Cancellation           N/A (no async)           takeUntil / abort
Memoization            Built-in (computed)      Manual (shareReplay)
OnPush integration     Auto-marks for check     Needs async pipe / markForCheck
Conceptual fit         "the current value of X" "the stream of X events over time"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ask one question:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"I need to know the latest X" -&amp;gt; &lt;strong&gt;Signal&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;"I need to react to every event of X over time" -&amp;gt; &lt;strong&gt;RxJS&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That resolves 90% of the real ambiguity.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Signals win (state)
&lt;/h2&gt;

&lt;p&gt;Local UI state, derived values, service-level shared state, side effects — all Signal territory. The service-level case is where the code shrinks most:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BEFORE - BehaviorSubject ceremony (29 lines)&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;dateRange$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DateRange&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;status$&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="c1"&gt;// ...asObservable(), setters, combineLatest, shareReplay...&lt;/span&gt;

&lt;span class="c1"&gt;// AFTER - Signals (9 lines)&lt;/span&gt;
&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;dateRange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DateRange&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;lastWeek&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;filters&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;dateRange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dateRange&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;computed()&lt;/code&gt; &lt;strong&gt;is&lt;/strong&gt; the multicast — lazy, memoized, O(1) cached reads. No &lt;code&gt;shareReplay&lt;/code&gt;, no &lt;code&gt;combineLatest&lt;/code&gt;, no &lt;code&gt;next()&lt;/code&gt;. Mattrx had 240 BehaviorSubjects; the cleanup deleted ~1,400 lines of state code.&lt;/p&gt;

&lt;h2&gt;
  
  
  When RxJS wins (events over time) — and Signals genuinely can't
&lt;/h2&gt;

&lt;p&gt;Debounced search with race cancellation is the canonical example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;results$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;valueChanges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;debounceTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;distinctUntilChanged&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/search?q=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;([])))),&lt;/span&gt;
  &lt;span class="nf"&gt;shareReplay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;takeUntilDestroyed&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To replicate this in pure Signals you'd hand-roll a &lt;code&gt;setTimeout&lt;/code&gt; debounce, an &lt;code&gt;AbortController&lt;/code&gt; you abort per keystroke, try/catch, and a loading flag — ~40 lines re-inventing &lt;code&gt;switchMap&lt;/code&gt;. Same story for &lt;strong&gt;WebSocket streams&lt;/strong&gt; (&lt;code&gt;webSocket()&lt;/code&gt; + &lt;code&gt;retry({delay})&lt;/code&gt; + &lt;code&gt;share()&lt;/code&gt;), &lt;strong&gt;drag-to-resize&lt;/strong&gt; (&lt;code&gt;mousedown -&amp;gt; switchMap(mousemove) -&amp;gt; takeUntil(mouseup)&lt;/code&gt;), and &lt;strong&gt;multi-source merge&lt;/strong&gt; (&lt;code&gt;combineLatest&lt;/code&gt; + &lt;code&gt;throttleTime&lt;/code&gt;). Anything with &lt;strong&gt;debounce / throttle / retry / timeout / switchMap / scan&lt;/strong&gt; in its description belongs in RxJS. &lt;strong&gt;Signals do not model time.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance (numbers, not vibes)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;signal()&lt;/code&gt; read&lt;/td&gt;
&lt;td&gt;~12 ns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;signal.set(v)&lt;/code&gt; write (no listeners)&lt;/td&gt;
&lt;td&gt;~50 ns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;BehaviorSubject.next(v)&lt;/code&gt; (one sync sub)&lt;/td&gt;
&lt;td&gt;~700 ns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;computed()&lt;/code&gt; read (warm cache)&lt;/td&gt;
&lt;td&gt;~15 ns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observable &lt;code&gt;pipe(map).subscribe()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;~3.4 us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Signals are ~14x faster than BehaviorSubject for "publish a value, one sync reader." But the real win is structural, not micro: on Mattrx's &lt;code&gt;/inbox&lt;/code&gt;, re-renders per WebSocket message went &lt;strong&gt;23 -&amp;gt; 2&lt;/strong&gt; — because fine-grained dependency tracking re-renders only the &lt;em&gt;specific slice&lt;/em&gt; that changed, not 23 components subscribed via &lt;code&gt;| async&lt;/code&gt;. And with &lt;strong&gt;zoneless&lt;/strong&gt; + Signals, idle change-detection passes on &lt;code&gt;/dashboard&lt;/code&gt; dropped to &lt;strong&gt;0&lt;/strong&gt; (only run when a signal changes).&lt;/p&gt;

&lt;p&gt;The honest caveat: Signals don't make a slow app fast on their own — they make change-detection &lt;strong&gt;precise&lt;/strong&gt;. The big wins come combined with OnPush + standalone + &lt;code&gt;@for&lt;/code&gt; track.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interop — you don't have to pick
&lt;/h2&gt;

&lt;p&gt;Bridge at the boundary and keep each half native:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// stream -&amp;gt; state (HTTP as an OnPush-aware Signal)&lt;/span&gt;
&lt;span class="nx"&gt;campaigns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;toSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Campaign&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/campaigns&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;initialValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// state -&amp;gt; stream (debounce a Signal-driven input through RxJS, back to a Signal)&lt;/span&gt;
&lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;toSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;toObservable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;debounceTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;distinctUntilChanged&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/search?q=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;initialValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;toSignal()&lt;/code&gt; and &lt;code&gt;toObservable()&lt;/code&gt; aren't workarounds — they're the design. (One gotcha: &lt;code&gt;toSignal&lt;/code&gt; without &lt;code&gt;initialValue&lt;/code&gt; returns &lt;code&gt;Signal&amp;lt;T | undefined&amp;gt;&lt;/code&gt; — always supply &lt;code&gt;initialValue&lt;/code&gt; for HTTP.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The decision tree
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Is this "the current value of X" (state)? -&amp;gt; SIGNAL
  ├── Local to a component -&amp;gt; signal()
  ├── Shared across the app -&amp;gt; signal() in a service
  └── Derived from other signals -&amp;gt; computed()
Otherwise it's an event stream / time-based / async:
  ├── HTTP -&amp;gt; HttpClient Observable; toSignal() if read as state
  ├── debounce/throttle/switchMap input -&amp;gt; RxJS
  ├── WebSocket / SSE -&amp;gt; RxJS (webSocket + retry + share)
  └── composing DOM events (drag, gesture) -&amp;gt; RxJS (fromEvent + operators)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The right mental model
&lt;/h2&gt;

&lt;p&gt;In one line: &lt;strong&gt;Signals are nouns. RxJS is verbs.&lt;/strong&gt; "What is the current set of selected campaigns?" -&amp;gt; Signal. "What's happening when the user types?" -&amp;gt; RxJS. Three habits: default to Signals for state, default to RxJS for streams, bridge with interop instead of fighting it.&lt;/p&gt;

&lt;p&gt;The full guide has all 10 code examples each way, the full benchmark tables, the end-to-end &lt;code&gt;/campaigns&lt;/code&gt; component using both, and the 4-week Mattrx migration path (including the bugs that bit us):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://prepstack.co.in/blog/angular-signals-vs-rxjs-when-to-use-which-performance-comparison-guide" rel="noopener noreferrer"&gt;https://prepstack.co.in/blog/angular-signals-vs-rxjs-when-to-use-which-performance-comparison-guide&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://prepstack.co.in/blog/angular-signals-vs-rxjs-when-to-use-which-performance-comparison-guide" rel="noopener noreferrer"&gt;PrepStack&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>rxjs</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Enterprise Angular Architecture in 2026 — Core, Shared, Feature + Nx Monorepo (Real Project Layout, Production Metrics)</title>
      <dc:creator>kirandeepjassal-crypto</dc:creator>
      <pubDate>Wed, 23 Sep 2026 18:44:42 +0000</pubDate>
      <link>https://dev.to/kirandeepjassalcrypto/enterprise-angular-architecture-in-2026-core-shared-feature-nx-monorepo-real-project-layout-1kd4</link>
      <guid>https://dev.to/kirandeepjassalcrypto/enterprise-angular-architecture-in-2026-core-shared-feature-nx-monorepo-real-project-layout-1kd4</guid>
      <description>&lt;p&gt;Most Angular apps don't fail because the framework runs out of steam. They fail around the 18-month mark, when the directory tree turns into a swamp: &lt;code&gt;shared/utils/helpers/index.ts&lt;/code&gt; re-exports everything, three teams import each other's internals through it, CI takes 14 minutes because &lt;em&gt;one&lt;/em&gt; test change rebuilds the world, and nobody can ship a feature without breaking two others.&lt;/p&gt;

&lt;p&gt;The four patterns here — &lt;strong&gt;Feature, Core, Shared, and an Nx monorepo&lt;/strong&gt; with enforced library boundaries — are what stops that. Not 2017 NgModule dogma; the &lt;em&gt;directory-and-dependency-graph discipline&lt;/em&gt; underneath, which works just as cleanly with Angular 19 standalone components.&lt;/p&gt;

&lt;p&gt;Every section uses the same real app: &lt;strong&gt;Mattrx&lt;/strong&gt;, a multi-tenant marketing-analytics SaaS — Angular 19 standalone, 4 apps in one repo, 540+ components, 22k LOC, 5 product teams sharing a design system and data-access layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model: the dependency graph IS the architecture
&lt;/h2&gt;

&lt;p&gt;The single biggest decision in a large Angular app is &lt;strong&gt;what's allowed to import what&lt;/strong&gt;. The arrows go ONE way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Apps (shells) -&amp;gt; Features (lazy) -&amp;gt; Shared (ui, util)
                     |
                     v
                   Core (imported only by the app shell)

Never:
  Shared -&amp;gt; Features    (shared can't know about features)
  Features -&amp;gt; Features  (features can't reach across each other)
  Anything -&amp;gt; Core, except the app shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Owns&lt;/th&gt;
&lt;th&gt;Imported by&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;auth, interceptors, error handler, config, logger&lt;/td&gt;
&lt;td&gt;only main.ts, once&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Shared&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;buttons, tables, pipes, DTOs - no business logic&lt;/td&gt;
&lt;td&gt;any feature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;routes, components, services, state for one capability&lt;/td&gt;
&lt;td&gt;the app router (lazy)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Nx libs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;tagged boundaries, ESLint enforcement, nx affected&lt;/td&gt;
&lt;td&gt;the whole repo&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Core — the app-singleton layer (modern, no NgModule)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;provideCore&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;EnvironmentProviders&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;makeEnvironmentProviders&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ConfigService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LoggerService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ErrorHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GlobalErrorHandler&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;provideHttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;withInterceptors&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;authInterceptor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errorInterceptor&lt;/span&gt;&lt;span class="p"&gt;])),&lt;/span&gt;
    &lt;span class="nf"&gt;provideAppInitializer&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ConfigService&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// apps/customer/src/main.ts — called exactly once&lt;/span&gt;
&lt;span class="nf"&gt;bootstrapApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;provideCore&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;provideRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;provideAnimationsAsync&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;makeEnvironmentProviders&lt;/code&gt; is the modern equivalent of the "Core module can only be imported once" guard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shared — the cardinal rule
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Shared cannot import from Features. Ever.&lt;/strong&gt; If a "shared" component needs to know about campaigns, it isn't shared — it's a campaigns component.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Each Shared component is its own Nx library, imported at the leaf — &lt;strong&gt;no barrel &lt;code&gt;@mattrx/shared/ui&lt;/code&gt; that re-exports everything&lt;/strong&gt; (so the bundler tree-shakes per-library, not per-monolith):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MxButton&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@mattrx/shared/ui/button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MxTable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@mattrx/shared/ui/table&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="s2"&gt;```

Don't ship a `&lt;/span&gt;&lt;span class="nx"&gt;SharedModule&lt;/span&gt;&lt;span class="s2"&gt;` in 2026 — importing it to use `&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;mx&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;` drags in `&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;mx&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;`, `&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;mx&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;toast&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;`, `&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;mx&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;`, and everything else. Use standalone leaves.

## Feature — one bounded business capability, lazy-loaded



```&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
&lt;span class="c1"&gt;// app.routes.ts — the app router doesn't know the feature's internal structure&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;campaigns&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;canMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;authGuard&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@mattrx/features/campaigns&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CAMPAIGNS_ROUTES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bundler emits one chunk per feature. Landing on /dashboard downloads main.js (~280 KB) + dashboard.chunk.js (~140 KB) — &lt;em&gt;not&lt;/em&gt; campaigns, inbox, reports. Feature state is Signals-first (toSignal at the HTTP boundary, computed for derived).&lt;/p&gt;

&lt;h2&gt;
  
  
  Nx — the structural firewall
&lt;/h2&gt;

&lt;p&gt;Tags declare what each library &lt;em&gt;is&lt;/em&gt; and &lt;em&gt;belongs to&lt;/em&gt;, and ESLint enforces the arrows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="nl"&gt;"@nx/enforce-module-boundaries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"depConstraints"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sourceTag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"type:feature"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nl"&gt;"onlyDependOnLibsWithTags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"type:ui"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"type:data-access"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"type:util"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sourceTag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"type:ui"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nl"&gt;"onlyDependOnLibsWithTags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"type:ui"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"type:util"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sourceTag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"type:util"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nl"&gt;"onlyDependOnLibsWithTags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"type:util"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sourceTag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"scope:customer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nl"&gt;"onlyDependOnLibsWithTags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"scope:customer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"scope:shared"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;type:ui&lt;/code&gt; library that imports a &lt;code&gt;type:feature&lt;/code&gt; library is an ESLint error in CI. That's the difference between "we have a convention" and "the codebase enforces the convention."&lt;/p&gt;

&lt;p&gt;And &lt;code&gt;nx affected&lt;/code&gt; runs CI only for what the PR touched:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx nx affected --target=build --base=origin/main&lt;/span&gt;   &lt;span class="c1"&gt;# 2.5 min, not 12&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The before/after (after the structure landed, 4 weeks)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CI on a typical PR&lt;/td&gt;
&lt;td&gt;22 min&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6 min&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;affected:build&lt;/td&gt;
&lt;td&gt;12 min&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.5 min&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;affected:test&lt;/td&gt;
&lt;td&gt;8 min&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;90 s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Initial JS (gzipped)&lt;/td&gt;
&lt;td&gt;1.2 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;290 KB&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-team merge conflicts/wk&lt;/td&gt;
&lt;td&gt;~6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scaffold a new feature&lt;/td&gt;
&lt;td&gt;~3 days&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~4 hours&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Where does this go?" PR comments/wk&lt;/td&gt;
&lt;td&gt;~12&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Velocity (features/sprint)&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;14&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The migration path (4 weeks, not one big PR)
&lt;/h2&gt;

&lt;p&gt;Week 1 — tease apart &lt;strong&gt;Core&lt;/strong&gt; (move Auth, interceptors, error handler, logger, config; replace &lt;code&gt;CoreModule&lt;/code&gt; with &lt;code&gt;provideCore()&lt;/code&gt;). Week 2 — tease apart &lt;strong&gt;Shared&lt;/strong&gt; (one lib per component, tag everything, turn on &lt;code&gt;@nx/enforce-module-boundaries&lt;/code&gt;, fix violations). Week 3 — extract &lt;strong&gt;Features&lt;/strong&gt; one at a time, most isolated first, ~1-2/day. Week 4 — enable &lt;code&gt;nx affected&lt;/code&gt; in CI + add any second frontend as a new app that reuses your shared libs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The right mental model
&lt;/h2&gt;

&lt;p&gt;Enterprise Angular at scale isn't NgModules vs standalone — it's &lt;strong&gt;the dependency graph being a layered DAG, and the codebase enforcing that picture so humans don't have to&lt;/strong&gt;. Core = app-singletons imported once. Shared = presentation + utilities that know no business concepts. Features = lazy-loaded leaves that can't reach each other. Nx = makes the graph visible, enforces it, makes CI fast.&lt;/p&gt;

&lt;p&gt;Three habits: generate every library (&lt;code&gt;nx g&lt;/code&gt;) with tags from day one; treat boundary violations as test failures; keep apps as thin shells.&lt;/p&gt;

&lt;p&gt;The full guide has the real Mattrx layout with file counts, the classic-vs-standalone code for every layer, the &lt;code&gt;nx graph&lt;/code&gt;, the full ESLint config, the decision tree for "where does this go?", and the week-by-week migration path:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://prepstack.co.in/blog/enterprise-angular-architecture-feature-core-shared-modules-nx-monorepo-guide" rel="noopener noreferrer"&gt;https://prepstack.co.in/blog/enterprise-angular-architecture-feature-core-shared-modules-nx-monorepo-guide&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://prepstack.co.in/blog/enterprise-angular-architecture-feature-core-shared-modules-nx-monorepo-guide" rel="noopener noreferrer"&gt;PrepStack&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>architecture</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>LLMs &amp; Transformers from First Principles (2026) — Tokenization, Attention, LoRA, and a Tiny GPT You Can Train (with PyTorch Code)</title>
      <dc:creator>kirandeepjassal-crypto</dc:creator>
      <pubDate>Mon, 21 Sep 2026 18:18:08 +0000</pubDate>
      <link>https://dev.to/kirandeepjassalcrypto/llms-transformers-from-first-principles-2026-tokenization-attention-lora-and-a-tiny-gpt-h13</link>
      <guid>https://dev.to/kirandeepjassalcrypto/llms-transformers-from-first-principles-2026-tokenization-attention-lora-and-a-tiny-gpt-h13</guid>
      <description>&lt;p&gt;Everyone uses LLMs in 2026. Far fewer can explain what happens between &lt;code&gt;text in&lt;/code&gt; and &lt;code&gt;text out&lt;/code&gt;. The gap matters because &lt;em&gt;every&lt;/em&gt; LLM problem — bad outputs, high latency, wrong answers, costly fine-tunes — is solved by knowing which mechanism inside the model is responsible.&lt;/p&gt;

&lt;p&gt;This rebuilds the LLM stack piece by piece with real PyTorch and Hugging Face code: tokenization, embeddings, self-attention, the transformer block, a tiny GPT you can train on your laptop, pretraining vs fine-tuning vs LoRA vs DPO, and decoding.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one idea
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;An LLM is a function from token sequences to a next-token probability distribution.&lt;/strong&gt; That's it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;sequence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;bos&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; sky&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; is&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;probs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LLM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;next_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;probs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every chat API, code assistant, agent, and RAG system is a sampling loop around "predict the next token."&lt;/p&gt;

&lt;h2&gt;
  
  
  Tokenization — text becomes integers first
&lt;/h2&gt;

&lt;p&gt;A model can't read characters. Modern LLMs use &lt;strong&gt;subword tokenization&lt;/strong&gt; (BPE for GPT/Llama/Mistral, WordPiece for BERT, SentencePiece for T5).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;
&lt;span class="n"&gt;tok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tok&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;convert_ids_to_tokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tok&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mumbai and Indore are cities in India.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# ['Mumbai', 'and', 'Ind', 'ore', 'are', 'cities', 'in', 'India', '.']
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Mumbai" is &lt;strong&gt;1 token&lt;/strong&gt;; "Indore" is &lt;strong&gt;2&lt;/strong&gt;. Token counts drive API cost, context window, and latency — French text costs 2-3x more tokens than English. &lt;strong&gt;Tokenization is the source of most "why does the model do X?" bugs.&lt;/strong&gt; And always use &lt;code&gt;apply_chat_template&lt;/code&gt; — hand-concatenating "user: ... assistant: ..." is a classic bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-attention — the one idea that changed everything
&lt;/h2&gt;

&lt;p&gt;For each token, compute a weighted sum of every other token's &lt;strong&gt;value&lt;/strong&gt;, where the weights depend on relevance. Every token gets three roles: Query ("what am I looking for?"), Key ("what do I represent?"), Value ("what do I contribute?").&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Attention(Q, K, V) = softmax(Q @ K.T / sqrt(d)) @ V
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The whole revolution is one matrix multiply + a softmax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Q&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transpose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d_k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;masked_fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-inf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;weights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;weights&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;causal mask&lt;/strong&gt; (lower-triangular) is why GPT can't see the future. &lt;strong&gt;Multi-head attention&lt;/strong&gt; runs several of these in parallel. In production, use Flash Attention via &lt;code&gt;F.scaled_dot_product_attention&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The transformer block
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x -&amp;gt; LayerNorm -&amp;gt; MultiHeadAttention -&amp;gt; +residual -&amp;gt;
  -&amp;gt; LayerNorm -&amp;gt; FeedForward -&amp;gt; +residual -&amp;gt; output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Residuals&lt;/strong&gt; are the gradient highway — without them, deep transformers don't train.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LayerNorm&lt;/strong&gt; (Pre-LN) stabilizes training.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feed-forward&lt;/strong&gt; is a 2-layer MLP per token, usually &lt;code&gt;d_ff = 4 x d_model&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stack 6-96 of these and you have a model. Llama-3-8B is 32 blocks; GPT-3 is 96. The guide has a full runnable ~200-line GPT you can train on Shakespeare on a laptop — &lt;strong&gt;that's the entire architecture of GPT-3, just bigger and on more data.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Training, decoded
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pretraining&lt;/strong&gt; = predict the next token on 5-15 trillion tokens. The intelligence emerges from that one boring objective at scale ($10M-$100M for a frontier model).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fine-tuning&lt;/strong&gt; — start with prompting/few-shot; if that's not enough, &lt;strong&gt;LoRA&lt;/strong&gt; trains ~0.1% of params at ~1000x less memory:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;lora_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoraConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lora_alpha&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;target_modules&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;q_proj&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;k_proj&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;v_proj&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;o_proj&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;lora_dropout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CAUSAL_LM&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_peft_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lora_config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# trainable%: 0.4%, adapter ~130 MB
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;QLoRA&lt;/strong&gt; (LoRA on a 4-bit base) fine-tunes a 70B model on a single 24 GB GPU — the standard recipe for small teams in 2026.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SFT&lt;/strong&gt; trains on (instruction, response); &lt;strong&gt;DPO&lt;/strong&gt; on (prompt, chosen, rejected) — much simpler than classic RLHF.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Decoding
&lt;/h2&gt;

&lt;p&gt;Greedy is deterministic but repetitive. The production default is temperature + top-p:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;do_sample&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_p&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;repetition_penalty&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1.05&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_new_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chat: &lt;code&gt;0.7&lt;/code&gt;. Code: &lt;code&gt;0.0-0.3&lt;/code&gt;. For production, swap &lt;code&gt;model.generate&lt;/code&gt; for &lt;strong&gt;vLLM&lt;/strong&gt; — paged attention + continuous batching, often 5-20x faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest stuff
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Context length costs scale &lt;strong&gt;quadratically&lt;/strong&gt; — 32k isn't 4x 8k, it's ~16x.&lt;/li&gt;
&lt;li&gt;Most prod LLM systems are 90% retrieval + 10% LLM.&lt;/li&gt;
&lt;li&gt;Fine-tuning is rarely the answer — try prompting, RAG, and a bigger model first.&lt;/li&gt;
&lt;li&gt;Evals beat vibes — build a golden set of 50-200 queries before you fine-tune.&lt;/li&gt;
&lt;li&gt;Inference cost dominates training cost. Optimize for serving.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The right mental model
&lt;/h2&gt;

&lt;p&gt;An LLM is not magic. It's: a tokenizer, an embedding table, a stack of transformer blocks, and a head that projects back to vocabulary. Pretraining gives general competence; fine-tuning teaches your task; decoding turns probabilities into text.&lt;/p&gt;

&lt;p&gt;Three habits: always inspect the tokens first; build the eval set before the model; reach for the smallest model that works.&lt;/p&gt;

&lt;p&gt;The full guide has the complete PyTorch — scaled dot-product + multi-head attention, the transformer block, the runnable tiny GPT + training loop, full/LoRA/QLoRA fine-tuning, DPO, the decoding recipes, RAG, tool-use, and the 2026 model menu:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://prepstack.co.in/blog/llms-transformers-tokenization-attention-embeddings-pretraining-finetuning-pytorch-guide" rel="noopener noreferrer"&gt;https://prepstack.co.in/blog/llms-transformers-tokenization-attention-embeddings-pretraining-finetuning-pytorch-guide&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://prepstack.co.in/blog/llms-transformers-tokenization-attention-embeddings-pretraining-finetuning-pytorch-guide" rel="noopener noreferrer"&gt;PrepStack&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>python</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
