<?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: Mohamed Mayallo</title>
    <description>The latest articles on DEV Community by Mohamed Mayallo (@mayallo).</description>
    <link>https://dev.to/mayallo</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F166826%2F9ddaf53f-bce9-4153-8ef4-3b017e231539.jpg</url>
      <title>DEV Community: Mohamed Mayallo</title>
      <link>https://dev.to/mayallo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mayallo"/>
    <language>en</language>
    <item>
      <title>Is SQL BETWEEN Inclusive or Exclusive?</title>
      <dc:creator>Mohamed Mayallo</dc:creator>
      <pubDate>Mon, 06 Oct 2025 10:20:00 +0000</pubDate>
      <link>https://dev.to/mayallo/is-sql-between-inclusive-or-exclusive-22b0</link>
      <guid>https://dev.to/mayallo/is-sql-between-inclusive-or-exclusive-22b0</guid>
      <description>&lt;h2&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;
The &lt;code&gt;SQL BETWEEN&lt;/code&gt; operator is &lt;strong&gt;inclusive&lt;/strong&gt;.  
That means both the lower and upper boundary values are included in the results.
&lt;/p&gt;

&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;
When writing SQL queries, many developers wonder: &lt;em&gt;is SQL BETWEEN inclusive or exclusive?&lt;/em&gt;  
The answer is simple: &lt;strong&gt;BETWEEN is inclusive&lt;/strong&gt;. This means that if you write &lt;code&gt;BETWEEN 10 AND 20&lt;/code&gt;, both &lt;code&gt;10&lt;/code&gt; and &lt;code&gt;20&lt;/code&gt; are part of the results.
&lt;/p&gt;

&lt;h2&gt;SQL BETWEEN Example&lt;/h2&gt;

&lt;p&gt;Imagine we have a table called &lt;code&gt;products&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;name&lt;/th&gt;
&lt;th&gt;price&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;Pen&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Notebook&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Bag&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Laptop&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;pre&gt;&lt;code&gt;
SELECT * 
FROM products
WHERE price BETWEEN 10 AND 20;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;name&lt;/th&gt;
&lt;th&gt;price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Notebook&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Bag&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;
&lt;strong&gt;Explanation:&lt;/strong&gt;&lt;br&gt;
Both &lt;code&gt;10&lt;/code&gt; and &lt;code&gt;20&lt;/code&gt; are included.  
That’s why we say &lt;strong&gt;SQL BETWEEN is inclusive&lt;/strong&gt;.
&lt;/p&gt;

&lt;h2&gt;SQL BETWEEN vs Greater Than and Less Than&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;
SELECT * 
FROM products
WHERE price &amp;gt;= 10 AND price &amp;lt;= 20;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This gives the &lt;strong&gt;same result&lt;/strong&gt; as using BETWEEN.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;name&lt;/th&gt;
&lt;th&gt;price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Notebook&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Bag&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So, &lt;strong&gt;BETWEEN = &amp;gt;= and &amp;lt;=&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;Common Misunderstanding&lt;/h2&gt;

&lt;p&gt;
Some developers think that &lt;code&gt;BETWEEN&lt;/code&gt; is exclusive (ignores boundaries). That’s wrong.  
If you wanted to exclude the edges, you would use &lt;code&gt;&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;&lt;/code&gt; instead:
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
SELECT * 
FROM products
WHERE price &amp;gt; 10 AND price &amp;lt; 20;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;name&lt;/th&gt;
&lt;th&gt;price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;
Here no rows match because only a price between 10 and 20 (like 15) would qualify, but our table doesn’t have that value.
&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;
So, is SQL BETWEEN inclusive or exclusive?  
The answer: &lt;strong&gt;SQL BETWEEN is inclusive&lt;/strong&gt;.
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It includes both boundary values.&lt;/li&gt;
  &lt;li&gt;It works the same as &lt;code&gt;&amp;gt;=&lt;/code&gt; and &lt;code&gt;&amp;lt;=&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;If you need exclusive ranges, use &lt;code&gt;&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
This makes &lt;code&gt;BETWEEN&lt;/code&gt; a very convenient way to filter data in an &lt;strong&gt;inclusive range&lt;/strong&gt;.
&lt;/p&gt;

&lt;p&gt;Finally, if you found this article helpful, you can check more here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mayallo.com/typescript-type-vs-interface/" rel="noopener noreferrer"&gt;TypeScript Type Vs Interface? The Answer Is Type!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mayallo.com/sql-coalesce-using-postgres/" rel="noopener noreferrer"&gt;SQL COALESCE in Postgres: A Simple Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mayallo.com/facade-vs-proxy-vs-adapter-design-patterns/" rel="noopener noreferrer"&gt;Facade vs Proxy vs Adapter Design Patterns&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>sql</category>
      <category>database</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Two Ways To Git Cherry-Pick From Another Repo</title>
      <dc:creator>Mohamed Mayallo</dc:creator>
      <pubDate>Thu, 02 Oct 2025 07:53:00 +0000</pubDate>
      <link>https://dev.to/mayallo/two-ways-to-git-cherry-pick-from-another-repo-5m5</link>
      <guid>https://dev.to/mayallo/two-ways-to-git-cherry-pick-from-another-repo-5m5</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When working with multiple repositories, there are times when you want to bring in just one (or a few) commits from another project, without merging the entire repo. In Git, you can cherry-pick from another repo by treating it like a remote.&lt;/p&gt;

&lt;p&gt;In this article, I’ll walk you through two steps with examples. Let's jump into them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why cherry-pick from an external repo?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  You want to reuse a bug fix or feature commit from another project.&lt;/li&gt;
&lt;li&gt;  You don’t want to merge all changes, just specific commits.&lt;/li&gt;
&lt;li&gt;  Keeps history clean by pulling only essential changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, cherry-picking across repos should be used carefully, because it can lead to duplicate content and conflicts.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Way: Using Cherry-Pick
&lt;/h2&gt;

&lt;p&gt;First of all, suppose your current repo is &lt;strong&gt;RepoA&lt;/strong&gt;, and you want a commit from &lt;strong&gt;RepoB&lt;/strong&gt; (on GitHub or Locally).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.  Add the external repo as a remote&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;git remote add repoB https://github.com/username/RepoB.git

&lt;span class="c"&gt;# or if the RepoB is local&lt;/span&gt;
git remote add repoB C:/Users/User/RepoB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;repoB&lt;/code&gt; is just a name (alias) for the external repository.&lt;br&gt;&lt;br&gt;
You can choose any name you like (e.g. &lt;code&gt;external&lt;/code&gt;, &lt;code&gt;upstream2&lt;/code&gt;, &lt;code&gt;sourceRepo&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;If you already have a remote with that name, pick a different alias.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.  Fetch from that remote&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;git fetch repoB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will bring all branches and commits from RepoB, so that your local Git can see them. You can now reference branches like &lt;code&gt;repoB/main&lt;/code&gt; or &lt;code&gt;repoB/feature-xyz&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.  Identify commit(s) you need&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You need the commit hash (SHA) you want to cherry-pick.&lt;/p&gt;

&lt;p&gt;List commits in a branch from the external remote:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log repoB/main &lt;span class="nt"&gt;--oneline&lt;/span&gt;

&lt;span class="c"&gt;# or&lt;/span&gt;

git log &lt;span class="nt"&gt;--graph&lt;/span&gt; &lt;span class="nt"&gt;--decorate&lt;/span&gt; repoB/main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you see the hash (say &lt;code&gt;abc1234&lt;/code&gt;), that’s the commit you want to pick.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.  Cherry-pick the commit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Switch to the branch in &lt;strong&gt;RepoA&lt;/strong&gt; where you want to apply the change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout my-feature-branch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now cherry-pick:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cherry-pick abc1234

&lt;span class="c"&gt;# or cherry-pick a range&lt;/span&gt;
git cherry-pick startSHA..endSHA

&lt;span class="c"&gt;# or multiple commits&lt;/span&gt;
git cherry-pick abc1234 def5678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will apply the changes from commit &lt;code&gt;abc1234&lt;/code&gt; into your branch, creating a new commit (with the same content, possibly a different hash).&lt;/p&gt;

&lt;p&gt;Then, resolve conflicts if any, or if you decide it's too messy or want to abort:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cherry-pick &lt;span class="nt"&gt;--abort&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That rolls back to the state before the cherry-pick started.&lt;/p&gt;

&lt;p&gt;Finally, don't forget to remove the remote if you no longer need it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote remove repoB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Second Way: Using format-patch
&lt;/h2&gt;

&lt;p&gt;In fact, it is a different way from cherry-picking, but it achieves our last goal.&lt;/p&gt;

&lt;p&gt;If you don’t want to add a remote, you can generate a patch file from the other repo and apply it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.  Generate the patch file:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;RepoB&lt;/strong&gt;, identify the commit hash you want to pick (as we did before), so export it into a patch file:&lt;/p&gt;

&lt;p&gt;So, in &lt;strong&gt;RepoB&lt;/strong&gt;, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git format-patch &lt;span class="nt"&gt;-1&lt;/span&gt; abc1234 &lt;span class="nt"&gt;--stdout&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; mypatch.patch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-1 abc1234&lt;/code&gt; means “one commit” (the one we want).&lt;br&gt;&lt;br&gt;
&lt;code&gt;--stdout&lt;/code&gt; emits the patch to stdout (redirected to file).&lt;/p&gt;

&lt;p&gt;Now you have a physical file (&lt;code&gt;mypatch.patch&lt;/code&gt;) in the &lt;code&gt;RepoB&lt;/code&gt; that represents the commit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.  Move this patch file to RepoA&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Copy &lt;code&gt;mypatch.patch&lt;/code&gt; into RepoA (can be via &lt;code&gt;cp&lt;/code&gt;, USB, email, etc.):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; /path/to/RepoB/mypatch.patch /path/to/RepoA/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.  Apply the patch in RepoA&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Then in &lt;strong&gt;RepoA&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;git apply mypatch.patch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method is useful when you can’t or don’t want to maintain a remote link.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep In Mind These Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Avoid cherry-picking too many commits across repos; it may cause duplicated code or merge confusion.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Always double-check commit context (dependencies); sometimes a commit depends on earlier ones you didn’t cherry-pick.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After you fetch from an external remote, avoid accidentally merging the remote branch unless you intend to.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In summary, to git cherry-pick from an external repo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Add the external repo as a remote&lt;/li&gt;
&lt;li&gt;  Fetch it&lt;/li&gt;
&lt;li&gt;  Identify commit(s)&lt;/li&gt;
&lt;li&gt;  Run &lt;code&gt;git cherry-pick&lt;/code&gt; (or patch method)&lt;/li&gt;
&lt;li&gt;  Resolve conflicts&lt;/li&gt;
&lt;li&gt;  Push your changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, if you found this article helpful, you can check more here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/sql-coalesce-using-postgres/" rel="noopener noreferrer"&gt;SQL COALESCE in Postgres: A Simple Guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/facade-vs-proxy-vs-adapter-design-patterns/" rel="noopener noreferrer"&gt;Facade vs Proxy vs Adapter Design Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/typescript-type-vs-interface/" rel="noopener noreferrer"&gt;TypeScript Type Vs Interface? The Answer Is Type!&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>github</category>
    </item>
    <item>
      <title>Untangle Your Code: Chain of Responsibility Design Pattern</title>
      <dc:creator>Mohamed Mayallo</dc:creator>
      <pubDate>Tue, 30 Sep 2025 07:22:04 +0000</pubDate>
      <link>https://dev.to/mayallo/untangle-your-code-chain-of-responsibility-design-pattern-2o1h</link>
      <guid>https://dev.to/mayallo/untangle-your-code-chain-of-responsibility-design-pattern-2o1h</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As developers, we’ve all been there: a single function bloated with a lot of responsibilities. It starts simple, and soon, the logic becomes a tangled mess that’s hard to read, maintain, and extend.&lt;/p&gt;

&lt;p&gt;The Chain of Responsibility Design Pattern is a behavioral design pattern that offers a clean escape from this complexity.&lt;/p&gt;

&lt;p&gt;It lets you pass a request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This allows you to decouple the sender of a request from its receivers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Case 1: A Messy Signup Form
&lt;/h2&gt;

&lt;p&gt;Imagine you're building a user registration feature. You need to validate the user's email, name, and password. Without a clear pattern, you might end up with something like this:&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;// A single function handling all validation&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateRegistration&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="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Validation for email&lt;/span&gt;
    &lt;span class="k"&gt;if &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="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&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="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="s2"&gt;Email seems okay.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Nested validation for name&lt;/span&gt;
        &lt;span class="k"&gt;if &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="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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="s2"&gt;Name is fine.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="c1"&gt;// More nested validation for password&lt;/span&gt;
            &lt;span class="k"&gt;if &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="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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="s2"&gt;Password is valid. All checks passed!&lt;/span&gt;&lt;span class="dl"&gt;"&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;true&lt;/span&gt;&lt;span class="p"&gt;;&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="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="s2"&gt;Error: Password is too short.&lt;/span&gt;&lt;span class="dl"&gt;"&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;false&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;else&lt;/span&gt; &lt;span class="p"&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="s2"&gt;Error: Name is too short.&lt;/span&gt;&lt;span class="dl"&gt;"&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;false&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;else&lt;/span&gt; &lt;span class="p"&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="s2"&gt;Error: Invalid email.&lt;/span&gt;&lt;span class="dl"&gt;"&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;false&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;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test@test.com&lt;/span&gt;&lt;span class="dl"&gt;"&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="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123456&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;validateRegistration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code works, but it's rigid. What if you need to add a new validation rule, like checking for password strength? You’d have to dive back into this nested logic, increasing the risk of breaking something.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution: A Clean Chain of Validators
&lt;/h3&gt;

&lt;p&gt;The Chain of Responsibility pattern solves this by breaking each validation rule into its own handler class. These handlers are then linked together in a sequence, or a "chain."&lt;/p&gt;

&lt;p&gt;A request enters the start of the chain and travels from handler to handler until one of them handles it or it reaches the end. For validation, if any handler finds an issue, it can break the chain.&lt;/p&gt;

&lt;p&gt;Here is how we can refactor our validation logic using the Chain of Responsibility pattern in TypeScript. This example creates a flexible input validation chain.&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;// Define the contract for every handler in the chain&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Handler&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="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// An abstract base class to provide default chaining behavior&lt;/span&gt;
&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseHandler&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Handler&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;nextHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Handler&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Sets the next handler in the chain and returns it,&lt;/span&gt;
    &lt;span class="c1"&gt;// allowing us to link handlers together fluently.&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;setNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Handler&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;nextHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;handler&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;handler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Executes the next handler if it exists. Subclasses will&lt;/span&gt;
    &lt;span class="c1"&gt;// call this after their own logic passes.&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextHandler&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;nextHandler&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="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// If this is the end of the chain, return true to signify success&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&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;// Concrete handler for validating an email&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IsEmailHandler&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseHandler&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;email&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="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&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;super&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;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;email&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="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;isValid&lt;/span&gt; &lt;span class="o"&gt;=&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;email&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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="s2"&gt;Valid email, passing to the next validator...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="c1"&gt;// If valid, call the next handler in the chain&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;super&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="p"&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="s2"&gt;Not a valid email, breaking the chain.&lt;/span&gt;&lt;span class="dl"&gt;"&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;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Break the chain&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Concrete handler for validating a name&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IsNameValidHandler&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseHandler&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;name&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="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&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;super&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&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="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;isValid&lt;/span&gt; &lt;span class="o"&gt;=&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;name&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&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="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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="s2"&gt;Valid name, passing to the next validator...&lt;/span&gt;&lt;span class="dl"&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;super&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="p"&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="s2"&gt;Not a valid name, breaking the chain.&lt;/span&gt;&lt;span class="dl"&gt;"&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;false&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;// Concrete handler for validating a password&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IsPasswordValidHandler&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseHandler&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;password&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="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&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;super&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;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;password&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="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;isValid&lt;/span&gt; &lt;span class="o"&gt;=&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;password&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&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="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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="s2"&gt;Valid password, all checks passed!&lt;/span&gt;&lt;span class="dl"&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;super&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="p"&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="s2"&gt;Not a valid password, breaking the chain.&lt;/span&gt;&lt;span class="dl"&gt;"&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;false&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;// --- Client Code ---&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userFormData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test@test.com&lt;/span&gt;&lt;span class="dl"&gt;"&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="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123456&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Create instances of our validators&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailValidator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IsEmailHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userFormData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&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;nameValidator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IsNameValidHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userFormData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&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;passwordValidator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IsPasswordValidHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userFormData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Build the chain of responsibility&lt;/span&gt;
&lt;span class="nx"&gt;emailValidator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nameValidator&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;passwordValidator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Start the validation process from the first handler&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="s2"&gt;Starting validation...&lt;/span&gt;&lt;span class="dl"&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;isAllValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;emailValidator&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isAllValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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="s2"&gt;Registration successful!&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&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="s2"&gt;Registration failed.&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;p&gt;Yes, for sure, more code, but have a closer look, it is significantly much cleaner. Each class has a &lt;a href="https://mayallo.com/solid-single-responsibility-principle/" rel="noopener noreferrer"&gt;single responsibility&lt;/a&gt;. Adding a new rule is as simple as creating a new handler class and inserting it into the chain, without modifying any existing code, which applies the &lt;a href="https://mayallo.com/solid-open-closed-principle/" rel="noopener noreferrer"&gt;Open-Closed Principle&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Case 2: API Middleware
&lt;/h2&gt;

&lt;p&gt;This is a very common use case. In web frameworks like Express.js, middleware functions form a chain of responsibility. An incoming HTTP request is passed through a series of middleware functions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  An &lt;code&gt;AuthMiddleware&lt;/code&gt; checks for a valid user token.&lt;/li&gt;
&lt;li&gt;  A &lt;code&gt;RoleMiddleware&lt;/code&gt; checks if the user has permission for the action.&lt;/li&gt;
&lt;li&gt;  A &lt;code&gt;LoginHandler&lt;/code&gt; handles the actual login logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each middleware can either pass the request to the next one or end the cycle by sending a response (e.g., a &lt;code&gt;401 Unauthorized&lt;/code&gt; error). This answers the common &lt;strong&gt;middleware vs chain of responsibility&lt;/strong&gt; question: middleware is a powerful, real-world implementation of this pattern.&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;// --- 1. Define the Request and Middleware Interface ---&lt;/span&gt;

&lt;span class="c1"&gt;// A simple representation of an incoming API request.&lt;/span&gt;
&lt;span class="c1"&gt;// The `user` property is optional because it's added by the AuthMiddleware.&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ApiRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;token&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="nl"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;data&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="nl"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&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;span class="c1"&gt;// The contract for any handler (middleware) in our chain.&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Middleware&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Middleware&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Middleware&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="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApiRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;message&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="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// --- 2. Create a Base Middleware Class for common logic ---&lt;/span&gt;

&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseMiddleware&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Middleware&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;nextHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Middleware&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;=&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;// This sets the next middleware in the chain.&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;setNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Middleware&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Middleware&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;nextHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;handler&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;handler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// This runs the next middleware if it exists.&lt;/span&gt;
    &lt;span class="c1"&gt;// Each concrete middleware will call this method if its check passes.&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApiRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;message&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="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;any&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextHandler&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;nextHandler&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="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// This is the default success response if it's the end of the chain.&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;success&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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Request processed successfully.&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;span class="c1"&gt;// --- 3. Implement Concrete Middleware Handlers ---&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Checks for a valid authentication token. If found, it "enriches" the
 * request by adding user information before passing it on.
 */&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthMiddleware&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseMiddleware&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApiRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;message&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="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&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;Checking authentication...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// In a real app, you'd validate a real token (e.g., JWT).&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-secret-token&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="c1"&gt;// Token is valid. Attach user info and pass to the next middleware.&lt;/span&gt;
            &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&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="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&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;Authentication successful. User attached.&lt;/span&gt;&lt;span class="dl"&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;super&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="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Token is invalid, so we break the chain here.&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;Authentication failed: Invalid token.&lt;/span&gt;&lt;span class="dl"&gt;'&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="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;401 Unauthorized: Invalid token.&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;span class="cm"&gt;/**
 * Checks if the user has the required role. This middleware assumes
 * AuthMiddleware has already run and attached a user object.
 */&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RoleMiddleware&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseMiddleware&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;requiredRole&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&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="k"&gt;super&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;requiredRole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;role&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="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApiRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;message&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="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&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="s2"&gt;`Checking authorization for role: &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;requiredRole&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;role&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;requiredRole&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// User has the required role. Pass to the next middleware.&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;Authorization successful.&lt;/span&gt;&lt;span class="dl"&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;super&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="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// User does not have the required role, so we break the chain.&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;Authorization failed: Insufficient permissions.&lt;/span&gt;&lt;span class="dl"&gt;'&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="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;403 Forbidden: Insufficient permissions.&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;span class="cm"&gt;/**
 * This is the final handler, representing the actual business logic
 */&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginHandler&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseMiddleware&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApiRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;message&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="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&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;Executing the login action...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// All checks passed, so process the request.&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;success&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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Data processed by login.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Hello, user &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&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="s2"&gt;! You processed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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="s2"&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="p"&gt;}&lt;/span&gt;


&lt;span class="c1"&gt;// --- 4. Client Code: Build and Run the Chain ---&lt;/span&gt;

&lt;span class="c1"&gt;// Create the middleware instances&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authCheck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AuthMiddleware&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;adminCheck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RoleMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&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;finalAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LoginHandler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Build the chain: Auth -&amp;gt; Role -&amp;gt; Action&lt;/span&gt;
&lt;span class="nx"&gt;authCheck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;adminCheck&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalAction&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;span class="c1"&gt;// --- TEST CASES ---&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;--- Test Case 1: Successful Request ---&lt;/span&gt;&lt;span class="dl"&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;successfulRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApiRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-secret-token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;important data&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;authCheck&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="nx"&gt;successfulRequest&lt;/span&gt;&lt;span class="p"&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;Result:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;--- Test Case 2: Authentication Failure ---&lt;/span&gt;&lt;span class="dl"&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;failedAuthRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApiRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;invalid-token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;some data&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="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;authCheck&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="nx"&gt;failedAuthRequest&lt;/span&gt;&lt;span class="p"&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;Result:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;--- Test Case 3: Authorization Failure ---&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// To test this, we'll temporarily change the user's role after a valid auth.&lt;/span&gt;
&lt;span class="c1"&gt;// In a real scenario, this would come from the database lookup in AuthMiddleware.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MockAuthMiddleware&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseMiddleware&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApiRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// Mock a non-admin user&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;super&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="nx"&gt;request&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;mockAuth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MockAuthMiddleware&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;mockAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;adminCheck&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalAction&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;failedRoleRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApiRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-secret-token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// Auth token is valid&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin data&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="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mockAuth&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="nx"&gt;failedRoleRequest&lt;/span&gt;&lt;span class="p"&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;Result:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, as you saw, each handler has its own responsibility, which increases the decoupling. On top of that, you might have noticed from the third test case that it makes unit testing remarkably much easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use the Chain of Responsibility Pattern
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  When you want to decouple the object that sends a request from the objects that process it.&lt;/li&gt;
&lt;li&gt;  When you need to execute handlers in a specific order.&lt;/li&gt;
&lt;li&gt;  When you want to add or remove responsible objects at runtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In short, the Chain of Responsibility pattern is more than just a theoretical concept; it's a practical solution to a common coding problem. By transforming a monolithic block of logic into a flexible chain of independent handlers, you gain code that is easier to &lt;strong&gt;read&lt;/strong&gt;, &lt;strong&gt;test&lt;/strong&gt;, and &lt;strong&gt;extend&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Refer to these resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://refactoring.guru/design-patterns/chain-of-responsibility/" rel="noopener noreferrer"&gt;Chain of Responsibility&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.digitalocean.com/community/tutorials/chain-of-responsibility-design-pattern-in-java" rel="noopener noreferrer"&gt;Chain of Responsibility Design Pattern in Java&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Think about it
&lt;/h2&gt;

&lt;p&gt;If you enjoyed this article, I’d truly appreciate it if you could share it—it really motivates me to keep creating more helpful content!&lt;/p&gt;

&lt;p&gt;If you're interested in exploring more, check out these articles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/asynchronous-javascript/" rel="noopener noreferrer"&gt;4 Ways to Handle Async Operations in Javascript&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/strategy-state-template-design-patterns/" rel="noopener noreferrer"&gt;Strategy vs State vs Template Design Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/mongodb-gridfs/" rel="noopener noreferrer"&gt;MongoDB GridFS, Made Simple&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for sticking with me until the end—I hope you found this article valuable and enjoyable!&lt;/p&gt;

</description>
      <category>designpatterns</category>
      <category>solidprinciples</category>
      <category>programming</category>
    </item>
    <item>
      <title>Do You Know The LATERAL JOIN In SQL?</title>
      <dc:creator>Mohamed Mayallo</dc:creator>
      <pubDate>Wed, 06 Aug 2025 07:02:00 +0000</pubDate>
      <link>https://dev.to/mayallo/do-you-know-the-lateral-join-in-sql-489l</link>
      <guid>https://dev.to/mayallo/do-you-know-the-lateral-join-in-sql-489l</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Have you ever been stuck trying to write a SQL query that needs to perform a sub-calculation &lt;em&gt;for each row&lt;/em&gt; of your main table? Maybe you needed to find the last 3 blog posts for every user, or the top 5 products for each category.&lt;/p&gt;

&lt;p&gt;These &lt;strong&gt;"for-each"&lt;/strong&gt; style problems can lead to complicated, slow, and hard-to-read queries. This is the exact problem the &lt;code&gt;LATERAL&lt;/code&gt; JOIN was designed to solve.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Does LATERAL Actually Mean?
&lt;/h2&gt;

&lt;p&gt;First, let's clarify a critical point. While it's common to hear "lateral join", the true power comes from the LATERAL keyword itself. It isn't a type of join like INNER or LEFT; it's a modifier that fundamentally changes how a subquery in the FROM clause behaves.&lt;/p&gt;

&lt;p&gt;Think of "lateral" as meaning "sideways." A standard subquery in a FROM clause is executed in isolation and cannot reference other tables in the same clause. The LATERAL keyword breaks this rule. It gives a subquery permission to &lt;strong&gt;look sideways&lt;/strong&gt; at columns from tables that appear before it in the FROM list.&lt;/p&gt;

&lt;p&gt;This enables a powerful for-each loop pattern directly in your SQL.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Real-World Business Problem (&lt;strong&gt;PostgreSQL&lt;/strong&gt;)
&lt;/h2&gt;

&lt;p&gt;Let's create an e-commerce scenario with customers, products, and orders to demonstrate LATERAL joins in action using PostgreSQL.&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="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&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="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;order_date&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;-- To store a list of products in the order&lt;/span&gt;
    &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="c1"&gt;-- To store tags like 'gift', 'rush_delivery'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Seed the tables with versatile data&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&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="s1"&gt;'Alice'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Bob'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Charlie'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;101&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="s1"&gt;'2025-01-15'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'[{"product": "Mouse", "price": 25.00}]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'{"sale"}'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;102&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="s1"&gt;'2025-06-20'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'[{"product": "Webcam", "price": 45.00}, {"product": "Keyboard", "price": 75.00}]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'{"work", "rush_delivery"}'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;103&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="s1"&gt;'2025-07-01'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'[{"product": "Mousepad", "price": 15.00}]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'{}'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;104&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2025-02-25'&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="s1"&gt;'[{"product": "Monitor", "price": 250.00}]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'{}'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;105&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2025-07-10'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'[{"product": "Keyboard", "price": 80.00}]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'{"urgent"}'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;106&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2025-04-05'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'[{"product": "Headphones", "price": 120.00}]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'{"gift", "rush_delivery"}'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The LATERAL Use Cases
&lt;/h2&gt;

&lt;p&gt;So, let's solve some challenges:&lt;/p&gt;

&lt;h3&gt;
  
  
  1- Selecting Top N Rows per Group
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; Find the 2 most recent orders for each customer.&lt;/p&gt;

&lt;p&gt;When you encounter this problem, you might think of some available options. Let's examine each option, and finally, we will use the LATERAL option.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1: The Window Function Approach&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a common way to solve top-N problems, but it requires multiple logical steps.&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;WITH&lt;/span&gt; &lt;span class="n"&gt;RankedOrders&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;-- Step 1: Scan all orders and assign a rank to each one within its customer group&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt;
        &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ROW_NUMBER&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;PARTITION&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&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;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_date&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;rn&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt;
        &lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;
    &lt;span class="k"&gt;JOIN&lt;/span&gt;
        &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-- Step 2: Select from the ranked results and filter for the ones you want&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;order_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="n"&gt;RankedOrders&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;
    &lt;span class="n"&gt;rn&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;2&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;Why it's less ideal:&lt;/strong&gt; While it works perfectly, the logic is indirect. You have to create a temporary ranked dataset of &lt;em&gt;all&lt;/em&gt; orders and then query it again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 2: The Correlated Subquery Approach&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A traditional correlated subquery is often used to fetch a single piece of related data.&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;-- This only works for a single value, not a full row.&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_date&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&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;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_date&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt; &lt;span class="k"&gt;LIMIT&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;AS&lt;/span&gt; &lt;span class="n"&gt;latest_order_date&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="k"&gt;c&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;Why it fails for this problem:&lt;/strong&gt; The fundamental limitation of a scalar subquery (one used in a &lt;code&gt;SELECT&lt;/code&gt; list) is that it &lt;strong&gt;must return exactly one column and one row&lt;/strong&gt;. It's physically impossible to use this technique to fetch the two full order records (with multiple columns like &lt;code&gt;order_date&lt;/code&gt; and &lt;code&gt;items&lt;/code&gt;) that our problem requires. It's the wrong tool for the job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 3: The &lt;code&gt;GROUP BY&lt;/code&gt; Approach&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GROUP BY&lt;/code&gt; is built for aggregation, not for retrieving individual rows from a group.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- This finds the latest date, but loses all other details of that order.
SELECT
    c.customer_name,
    MAX(o.order_date) AS latest_order_date
FROM
    customers c
JOIN
    orders o ON c.customer_id = o.customer_id
GROUP BY
    c.customer_name;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it fails for this problem:&lt;/strong&gt; The entire purpose of &lt;code&gt;GROUP BY&lt;/code&gt; is to collapse many rows into a single summary row. It can give you the latest date, the total count, or the average amount, but it discards the individual rows in the process. You cannot use it to select the "top 2" original rows from the group.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 4: The &lt;code&gt;LATERAL&lt;/code&gt; Solution&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;SELECT
    c.customer_name,
    recent_orders.order_date,
    recent_orders.items
FROM
    customers c
LEFT JOIN LATERAL (
    SELECT
        o.order_date,
        o.items
    FROM
        orders o
    WHERE
        o.customer_id = c.customer_id
    ORDER BY
        o.order_date DESC
    LIMIT 2
) AS recent_orders ON true;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you see, it reads like a direct translation of our request: "For each customer, get their two most recent orders."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; The &lt;code&gt;ON TRUE&lt;/code&gt; clause is used since we’re not joining on specific columns but including the subquery’s results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But why is it better than the Window Function approach?&lt;/strong&gt; The &lt;code&gt;LATERAL&lt;/code&gt; approach feels more natural because it integrates the filtering (&lt;code&gt;LIMIT 2&lt;/code&gt;) directly into the "for-each-customer" step, avoiding the separate ranking-then-filtering process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;customer_name&lt;/th&gt;
&lt;th&gt;order_date&lt;/th&gt;
&lt;th&gt;items&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;2025-07-01&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[{"product": "Mousepad", "price": 15.00}]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;2025-06-20&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[{"product": "Webcam", "price": 45.00}, {"product": "Keyboard", "price": 75.00}]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob&lt;/td&gt;
&lt;td&gt;2025-07-10&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[{"product": "Keyboard", "price": 80.00}]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob&lt;/td&gt;
&lt;td&gt;2025-02-25&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[{"product": "Monitor", "price": 250.00}]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Charlie&lt;/td&gt;
&lt;td&gt;2025-04-05&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[{"product": "Headphones", "price": 120.00}]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  2- Unpacking JSONB Order Details
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; Find all customers who have ever ordered a 'Keyboard'.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT DISTINCT -- Use DISTINCT to only list each customer once
    c.customer_name
FROM
    orders o
JOIN
    customers c ON o.customer_id = c.customer_id
-- For each order 'o', expand its items into a table called 'item_details'
JOIN LATERAL jsonb_to_recordset(o.items) AS item_details(product TEXT, price DECIMAL) ON true
WHERE
    item_details.product = 'Keyboard';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function &lt;code&gt;jsonb_to_recordset&lt;/code&gt; turns a JSON array into a virtual table. &lt;code&gt;LATERAL&lt;/code&gt; lets us run this function for every single order row.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;customer_name&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  3- Searching Array Data With UNNEST
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; Find the names and order dates for all orders tagged with 'rush_delivery'.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT
    c.customer_name,
    o.order_date,
    tag_value
FROM
    orders o
JOIN
    customers c ON o.customer_id = c.customer_id
-- For each order 'o', expand its tags array into a single-column table
, LATERAL unnest(o.tags) AS tag_value
WHERE
    tag_value = 'rush_delivery';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;unnest&lt;/code&gt; function expands an array into a set of rows. &lt;code&gt;LATERAL&lt;/code&gt; lets us do this for each order's &lt;code&gt;tags&lt;/code&gt; array.&lt;/p&gt;

&lt;p&gt;However, PostgreSQL allows you to &lt;strong&gt;omit &lt;code&gt;LATERAL&lt;/code&gt;&lt;/strong&gt; in some cases &lt;strong&gt;implicitly&lt;/strong&gt;. When you use a set-returning function like &lt;code&gt;unnest()&lt;/code&gt; in the &lt;code&gt;FROM&lt;/code&gt; clause with a table column as argument (e.g., &lt;code&gt;o.tags&lt;/code&gt;), PostgreSQL treats it as a &lt;strong&gt;LATERAL&lt;/strong&gt; join &lt;em&gt;implicitly&lt;/em&gt;. So, in this case you can remove &lt;code&gt;LATERAL&lt;/code&gt; and the query will work; but it is best practice to keep&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Keep in mind that the &lt;code&gt;,&lt;/code&gt; is a shorthand for &lt;code&gt;CORSS JOIN&lt;/code&gt;; which means it should be &lt;code&gt;CROSS JOIN LATERAL&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;customer_name&lt;/th&gt;
&lt;th&gt;order_date&lt;/th&gt;
&lt;th&gt;tag_value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;2025-06-20&lt;/td&gt;
&lt;td&gt;rush_delivery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Charlie&lt;/td&gt;
&lt;td&gt;2025-04-05&lt;/td&gt;
&lt;td&gt;rush_delivery&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  4- Using Functions and Calculations per Row
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; Apply a 10% discount if the order amount exceeds 100.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT 
    c.customer_name,
    o.amount,
    d.discount
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
CROSS JOIN LATERAL (
    SELECT CASE 
        WHEN o.amount &amp;gt; 100 THEN o.amount * 0.1 
        ELSE 0 
    END AS discount
) d;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;customer_name&lt;/th&gt;
&lt;th&gt;amount&lt;/th&gt;
&lt;th&gt;discount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Charlie&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  LATERAL JOIN vs. Correlated Subqueries
&lt;/h2&gt;

&lt;p&gt;Correlated subqueries and &lt;code&gt;LATERAL JOIN&lt;/code&gt;s in SQL both allow a subquery to reference columns from a preceding table; however, they differ in their capabilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Correlated Subqueries:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A traditional correlated subquery must return a single scalar value (one column, one row) for each row processed by the outer query.&lt;/li&gt;
&lt;li&gt;  They are typically found in the &lt;code&gt;SELECT&lt;/code&gt; list, &lt;code&gt;WHERE&lt;/code&gt; clause, or &lt;code&gt;HAVING&lt;/code&gt; clause.&lt;/li&gt;
&lt;li&gt;  It runs repeatedly for each row, which might lead to scanning the target table multiple times.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;LATERAL JOIN:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A &lt;code&gt;LATERAL JOIN&lt;/code&gt; can return multiple columns and multiple rows from the subquery for each row of the outer query.&lt;/li&gt;
&lt;li&gt;  It is placed in the &lt;code&gt;FROM&lt;/code&gt; clause, acting as a join between the outer table and the result of the &lt;code&gt;LATERAL&lt;/code&gt; subquery.&lt;/li&gt;
&lt;li&gt;  Allows PostgreSQL to plan the subquery execution more efficiently, potentially reducing table scans.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Avoid LATERAL?
&lt;/h2&gt;

&lt;p&gt;An expert knows when &lt;em&gt;not&lt;/em&gt; to use a tool. &lt;code&gt;LATERAL&lt;/code&gt; is a specialized solution, and using it for simpler problems is inefficient and overly complex. Let's introduce some use cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Case 1: For the "Top-1" Problem, Use &lt;code&gt;DISTINCT ON&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;If you only need the &lt;em&gt;single&lt;/em&gt; most recent record, &lt;code&gt;DISTINCT ON&lt;/code&gt; is purpose-built, more declarative, and often faster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Better way to get ONLY the single most recent order
SELECT DISTINCT ON (c.customer_id)
    c.customer_name,
    o.order_date
FROM
    customers c
JOIN
    orders o ON c.customer_id = o.customer_id
ORDER BY
    c.customer_id, o.order_date DESC;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it's better:&lt;/strong&gt; &lt;code&gt;DISTINCT ON&lt;/code&gt; is the idiomatic PostgreSQL solution for the "top-1" problem. Its intent is clearer, and the query planner can often optimize it more effectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Case 2: For Simple Aggregates, Use &lt;code&gt;GROUP BY&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;If you only need a summary calculation (&lt;code&gt;COUNT&lt;/code&gt;, &lt;code&gt;SUM&lt;/code&gt;, &lt;code&gt;AVG&lt;/code&gt;) and not the details of the individual rows, &lt;code&gt;GROUP BY&lt;/code&gt; is the correct, standard tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Get the total number of orders for each customer
SELECT
    c.customer_name,
    COUNT(o.order_id) AS total_orders
FROM
    customers c
JOIN
    orders o ON c.customer_id = o.customer_id
GROUP BY
    c.customer_name;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it's better:&lt;/strong&gt; This is the most fundamental and efficient way to perform aggregations. Using &lt;code&gt;LATERAL&lt;/code&gt; to count rows would be a convoluted anti-pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Considerations
&lt;/h2&gt;

&lt;p&gt;LATERAL can improve performance over correlated subqueries because PostgreSQL’s query planner can optimize them better. However:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Index Usage&lt;/strong&gt;: Ensure indexes exist on join conditions (e.g., customer_id in the orders table).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Data Volume&lt;/strong&gt;: For large datasets, test performance to avoid excessive subquery executions.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Query Complexity&lt;/strong&gt;: Complex LATERAL subqueries may still be resource-intensive if not optimized.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: Use EXPLAIN to analyze the query plan and ensure indexes are used effectively.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE INDEX idx_orders_customer_id ON orders(customer_id);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;LATERAL joins in PostgreSQL are a game-changer for handling complex queries with clarity and efficiency. From extracting JSONB data to selecting top N rows per group, they offer flexibility that traditional joins and correlated subqueries often lack.&lt;/p&gt;

&lt;p&gt;By understanding when to use LATERAL joins, optimizing performance with indexes, and avoiding overuse in simple scenarios, you can unlock their full potential.&lt;/p&gt;

&lt;p&gt;Try experimenting with LATERAL in your next PostgreSQL project, and see how it simplifies your data challenges!&lt;/p&gt;

&lt;p&gt;If you’re interested in exploring more, check out these articles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/sql-filter-clause-postgres/" rel="noopener noreferrer"&gt;Postgres SQL FILTER: A Smarter CASE and CTE Alternative&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/sql-coalesce-using-postgres/" rel="noopener noreferrer"&gt;SQL COALESCE in Postgres: A Simple Guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/typescript-omit-multiple-keys/" rel="noopener noreferrer"&gt;How to Omit Multiple Keys in TypeScript&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/overloading-vs-overriding-typescript/" rel="noopener noreferrer"&gt;Overloading vs. Overriding in TypeScript&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>database</category>
      <category>postgres</category>
      <category>sql</category>
    </item>
    <item>
      <title>Postgres SQL FILTER: A Smarter CASE and CTE Alternative</title>
      <dc:creator>Mohamed Mayallo</dc:creator>
      <pubDate>Mon, 30 Jun 2025 07:06:00 +0000</pubDate>
      <link>https://dev.to/mayallo/postgres-sql-filter-a-smarter-case-and-cte-alternative-2l63</link>
      <guid>https://dev.to/mayallo/postgres-sql-filter-a-smarter-case-and-cte-alternative-2l63</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When you build reports in SQL, you often need to count or average values based on a condition, like counting only completed orders or averaging amounts for canceled ones.&lt;/p&gt;

&lt;p&gt;For years, SQL developers relied on &lt;code&gt;CASE&lt;/code&gt; statements or complex &lt;code&gt;Common Table Expressions (CTEs)&lt;/code&gt; to handle these scenarios. They work, but it gets messy fast.&lt;/p&gt;

&lt;p&gt;There's a better way.&lt;/p&gt;

&lt;p&gt;PostgreSQL (and some other databases) support the &lt;code&gt;FILTER&lt;/code&gt; clause, a clean and efficient feature for conditional aggregation. In this guide, you’ll learn how to use it to simplify your queries, boost performance, and avoid common mistakes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Business Problem: An E-commerce Dashboard
&lt;/h2&gt;

&lt;p&gt;Imagine you run an online store. To understand your business's health, you need a monthly report that shows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; The total revenue from all orders.&lt;/li&gt;
&lt;li&gt; The revenue generated specifically from "completed" orders.&lt;/li&gt;
&lt;li&gt; The revenue lost from "cancelled" orders.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Getting this data in one clean report requires us to aggregate sums based on the status of each order.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Our Example
&lt;/h2&gt;

&lt;p&gt;First, let's create the tables we need. We'll have a &lt;code&gt;customers&lt;/code&gt; table and an &lt;code&gt;orders&lt;/code&gt; table.&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;-- Create a table for our customers&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&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;join_date&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Create a table for orders&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;order_date&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;order_status&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&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="c1"&gt;-- e.g., 'completed', 'pending', 'cancelled'&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="nb"&gt;DECIMAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Insert some sample data to work with&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;join_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&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="s1"&gt;'John Smith'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2023-01-15'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Jane Doe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2023-02-20'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order_status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;101&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="s1"&gt;'2024-05-05'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'completed'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;102&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2024-05-10'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'completed'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;103&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="s1"&gt;'2024-05-12'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'cancelled'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;104&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2024-06-01'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'completed'&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="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;105&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="s1"&gt;'2024-06-03'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'pending'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;106&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2024-06-08'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'cancelled'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;107&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="s1"&gt;'2024-06-15'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'completed'&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="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our goal is to create the following monthly summary from this data.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;month&lt;/th&gt;
&lt;th&gt;total_revenue&lt;/th&gt;
&lt;th&gt;completed_revenue&lt;/th&gt;
&lt;th&gt;cancelled_revenue&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2024-05&lt;/td&gt;
&lt;td&gt;425.75&lt;/td&gt;
&lt;td&gt;350.50&lt;/td&gt;
&lt;td&gt;75.25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2024-06&lt;/td&gt;
&lt;td&gt;720.75&lt;/td&gt;
&lt;td&gt;550.00&lt;/td&gt;
&lt;td&gt;120.75&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Solution 1: Using the CASE Statement
&lt;/h2&gt;

&lt;p&gt;The most common method for PostgreSQL conditional count and sum was the &lt;code&gt;CASE&lt;/code&gt; statement inside an aggregate function.&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;-- This query uses CASE to conditionally sum the amounts.&lt;/span&gt;
&lt;span class="c1"&gt;-- It works, but it can get messy.&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;TO_CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'YYYY-MM'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;-- Sum all orders for total revenue&lt;/span&gt;
    &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_revenue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;-- Only sum if the status is 'completed'&lt;/span&gt;
    &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;order_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'completed'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;completed_revenue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;-- Only sum if the status is 'cancelled'&lt;/span&gt;
    &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;order_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'cancelled'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;cancelled_revenue&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt;
    &lt;span class="k"&gt;month&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt;
    &lt;span class="k"&gt;month&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This query gets the job done. However, for every conditional sum, you have a &lt;code&gt;CASE...WHEN...THEN...ELSE...END&lt;/code&gt; block. If you have many conditions, the &lt;code&gt;SELECT&lt;/code&gt; list becomes long, hard to read, and difficult to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution 2: Using Common Table Expressions (CTEs)
&lt;/h2&gt;

&lt;p&gt;Another approach is to use CTEs to pre-aggregate each status separately and then join them.&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;-- This query uses CTEs, which is even more verbose.&lt;/span&gt;
&lt;span class="c1"&gt;-- It breaks the logic into steps, but is much longer.&lt;/span&gt;
&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;monthly_totals&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt;
        &lt;span class="n"&gt;TO_CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'YYYY-MM'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_revenue&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
    &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;month&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;completed&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt;
        &lt;span class="n"&gt;TO_CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'YYYY-MM'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;completed_revenue&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;order_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'completed'&lt;/span&gt;
    &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;month&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;cancelled&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt;
        &lt;span class="n"&gt;TO_CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'YYYY-MM'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;cancelled_revenue&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;order_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'cancelled'&lt;/span&gt;
    &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;month&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;mt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;mt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_revenue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;COALESCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completed_revenue&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="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;completed_revenue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;COALESCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cancelled_revenue&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="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;cancelled_revenue&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="n"&gt;monthly_totals&lt;/span&gt; &lt;span class="n"&gt;mt&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;completed&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;mt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;month&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;month&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;cancelled&lt;/span&gt; &lt;span class="n"&gt;cn&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;mt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;month&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;month&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;mt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;month&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is extremely verbose. It requires multiple scans of the &lt;code&gt;orders&lt;/code&gt; table (though the optimizer might fix this) and complex joins. It's simply too much code for such a common task.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Better Way: The FILTER Clause
&lt;/h2&gt;

&lt;p&gt;Now, let's solve the same problem using the &lt;code&gt;FILTER&lt;/code&gt; clause.&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;-- This is the modern, clean, and efficient way.&lt;/span&gt;
&lt;span class="c1"&gt;-- Notice how much easier it is to read.&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;TO_CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'YYYY-MM'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;-- Sum all orders for total revenue&lt;/span&gt;
    &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_revenue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;-- The FILTER clause applies a WHERE condition to the aggregation&lt;/span&gt;
    &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;FILTER&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;order_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'completed'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;completed_revenue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;FILTER&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;order_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'cancelled'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;cancelled_revenue&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt;
    &lt;span class="k"&gt;month&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt;
    &lt;span class="k"&gt;month&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is identical, but the query is dramatically cleaner. The &lt;code&gt;FILTER (WHERE ...)&lt;/code&gt; syntax is attached directly to the SQL aggregate function &lt;code&gt;FILTER&lt;/code&gt;, making the intent crystal clear: "Sum the amount, but only for rows that meet this condition." This makes it perfect for creating &lt;strong&gt;SQL pivot with filter&lt;/strong&gt;-like reports.&lt;/p&gt;

&lt;h2&gt;
  
  
  FILTER vs. CASE: A Closer Look
&lt;/h2&gt;

&lt;p&gt;Readability is a huge win, but what about performance?&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;Postgres FILTER vs CASE&lt;/strong&gt; debate, according to &lt;a href="https://blog.jooq.org/the-performance-impact-of-sqls-filter-clause/" rel="noopener noreferrer"&gt;jOOQ’s benchmark&lt;/a&gt;, &lt;code&gt;FILTER&lt;/code&gt; often has a performance edge. While logically similar, &lt;code&gt;FILTER&lt;/code&gt; provides a more direct instruction to the PostgreSQL query planner.&lt;/p&gt;

&lt;p&gt;Why? The &lt;code&gt;CASE&lt;/code&gt; statement is a general-purpose expression that can be used anywhere, so the optimizer has to work harder to understand its context within an aggregate function. The &lt;code&gt;FILTER&lt;/code&gt; clause, however, was designed specifically for this purpose, allowing for a more direct and optimized execution path.&lt;/p&gt;

&lt;h2&gt;
  
  
  FILTER vs. CTEs
&lt;/h2&gt;

&lt;p&gt;When it comes to &lt;strong&gt;CTE vs FILTER&lt;/strong&gt;, the choice is even clearer for conditional aggregation. The CTE approach requires multiple subqueries and joins, which adds significant overhead both in terms of code length and planner complexity. The &lt;code&gt;FILTER&lt;/code&gt; clause accomplishes the same goal in a single, streamlined scan of the table, making it vastly more efficient and maintainable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using FILTER with Multiple Conditions
&lt;/h2&gt;

&lt;p&gt;What if you need to check multiple criteria? The &lt;code&gt;FILTER&lt;/code&gt; clause supports standard &lt;code&gt;AND&lt;/code&gt; and &lt;code&gt;OR&lt;/code&gt; logic inside its &lt;code&gt;WHERE&lt;/code&gt; clause, making a PostgreSQL filter multiple conditions check straightforward.&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;-- Example of filtering on multiple conditions&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="k"&gt;COUNT&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="n"&gt;FILTER&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;order_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'completed'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;large_completed_orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;COUNT&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="n"&gt;FILTER&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;order_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'pending'&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;order_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'shipped'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;in_progress_orders&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The PostgreSQL &lt;code&gt;FILTER&lt;/code&gt; clause is more than just syntactic sugar. It is a powerful tool for writing cleaner, more readable, and more performant SQL. By allowing you to apply specific conditions directly to aggregate functions, it solves the problem of PostgreSQL's conditional aggregation in a way that is far superior to older methods.&lt;/p&gt;

&lt;p&gt;For any data analyst or developer working with PostgreSQL, mastering the &lt;code&gt;FILTER&lt;/code&gt; clause is essential. It simplifies complex reports, speeds up queries, and makes your SQL code a joy to read and maintain. The next time you find yourself writing a &lt;code&gt;CASE&lt;/code&gt; statement inside a &lt;code&gt;SUM()&lt;/code&gt; or &lt;code&gt;COUNT()&lt;/code&gt;, give &lt;code&gt;FILTER&lt;/code&gt; a try. You won't look back.&lt;/p&gt;

&lt;p&gt;Finally, if you found this article helpful, you can check more here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/sql-coalesce-using-postgres/" rel="noopener noreferrer"&gt;SQL COALESCE in Postgres: A Simple Guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/facade-vs-proxy-vs-adapter-design-patterns/" rel="noopener noreferrer"&gt;Facade vs Proxy vs Adapter Design Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/typescript-type-vs-interface/" rel="noopener noreferrer"&gt;TypeScript Type Vs Interface? The Answer Is Type!&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>postgres</category>
      <category>sql</category>
      <category>database</category>
    </item>
    <item>
      <title>Can GraphQL Call REST API?</title>
      <dc:creator>Mohamed Mayallo</dc:creator>
      <pubDate>Wed, 18 Jun 2025 07:00:00 +0000</pubDate>
      <link>https://dev.to/mayallo/can-graphql-call-rest-api-4h9h</link>
      <guid>https://dev.to/mayallo/can-graphql-call-rest-api-4h9h</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Yes, GraphQL can call REST APIs. In fact, this is a common way to use GraphQL in real projects. It lets you use your existing REST services while giving frontend apps the flexibility of GraphQL.&lt;/p&gt;

&lt;p&gt;In this article, you’ll learn how to call REST from GraphQL using a very simple and practical method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use GraphQL with REST?
&lt;/h2&gt;

&lt;p&gt;Many apps already have REST APIs. Instead of replacing them completely, you can wrap those APIs with GraphQL. This lets frontend developers ask only for the data they need, without changing your backend.&lt;/p&gt;

&lt;p&gt;You get the best of both worlds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Use existing REST endpoints&lt;/li&gt;
&lt;li&gt;  Expose a cleaner GraphQL API to clients&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Let’s Build It Step-by-Step
&lt;/h2&gt;

&lt;p&gt;We’ll create a GraphQL server using &lt;strong&gt;Node.js&lt;/strong&gt;, and we’ll call a public REST API:&lt;br&gt;&lt;br&gt;
&lt;code&gt;https://jsonplaceholder.typicode.com/users/:id&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is a fake REST API that returns fake user data. It’s perfect for testing.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Set Up Project
&lt;/h3&gt;

&lt;p&gt;Make a new folder and install the packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;graphql-rest-example
&lt;span class="nb"&gt;cd &lt;/span&gt;graphql-rest-example
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;express express-graphql graphql axios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Create the GraphQL Server
&lt;/h3&gt;

&lt;p&gt;Create a file called &lt;code&gt;index.js&lt;/code&gt;:&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;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;graphqlHTTP&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express-graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;buildSchema&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;graphql&lt;/span&gt;&lt;span class="dl"&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;axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Step 1: Define GraphQL schema&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;buildSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
  type User {
    id: ID
    name: String
    username: String
    email: String
  }

  type Query {
    user(id: ID!): User
  }
`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Step 2: Define resolver that calls REST API&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;user&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="nx"&gt;id&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&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;`https://jsonplaceholder.typicode.com/users/&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="s2"&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&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;// Step 3: Create Express server&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;graphqlHTTP&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;rootValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;graphiql&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// Enable UI&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4000&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="p"&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;GraphQL server running at http://localhost:4000/graphql&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;h3&gt;
  
  
  Step 3: Run the Server
&lt;/h3&gt;

&lt;p&gt;Start the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open your browser and go to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;http://localhost:4000/graphql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll see a GraphQL UI where you can run this query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  user(id: 1) {
    id
    name
    email
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will return this result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&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;"user"&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Leanne Graham"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sincere@april.biz"&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This proves that you can call a REST API from GraphQL using a resolver.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you were wondering can GraphQL call REST API? Now you know the answer is &lt;strong&gt;yes&lt;/strong&gt;, and it's quite simple. By calling REST endpoints from your resolvers, you can keep your backend logic and still enjoy the benefits of GraphQL on the frontend.&lt;/p&gt;

&lt;p&gt;This method is clean, fast to implement, and great for gradually modernizing your stack.&lt;/p&gt;

&lt;p&gt;Finally, if you found this article useful, you can check more here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/inner-join-3-tables-sql/" rel="noopener noreferrer"&gt;How to Inner Join 3 Tables in SQL&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/facade-vs-proxy-vs-adapter-design-patterns/" rel="noopener noreferrer"&gt;Facade vs Proxy vs Adapter Design Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/typescript-type-vs-interface/" rel="noopener noreferrer"&gt;TypeScript Type Vs Interface? The Answer Is Type!&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>graphql</category>
      <category>webdev</category>
      <category>programming</category>
      <category>node</category>
    </item>
    <item>
      <title>Are Nx Monorepo Configurations Really Complex?</title>
      <dc:creator>Mohamed Mayallo</dc:creator>
      <pubDate>Tue, 17 Jun 2025 17:57:02 +0000</pubDate>
      <link>https://dev.to/mayallo/are-nx-monorepo-configurations-really-complex-l0l</link>
      <guid>https://dev.to/mayallo/are-nx-monorepo-configurations-really-complex-l0l</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This is the second part of our Nx monorepo series. If you haven't yet, you might want to check out the first article, &lt;a href="https://mayallo.com/nx-monorepo-nodejs-react/" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://mayallo.com/nx-monorepo-nodejs-react/" rel="noopener noreferrer"&gt;Nx Monorepo Guide: React &amp;amp; Node Fullstack App&lt;/a&gt;, where I talked about setting up an Nx workspace.&lt;/p&gt;

&lt;p&gt;Now, we'll dive into something more specific, yet very important: how TypeScript works inside Nx. Many developers, myself included, often get lost in all the &lt;code&gt;tsconfig&lt;/code&gt; files. Do you find yourself wondering what each one does? I know it can be too much to handle at first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Nx TypeScript Configuration Feels Complex
&lt;/h2&gt;

&lt;p&gt;The complexity comes from Nx managing TypeScript across dozens of apps and libraries. Unlike traditional single-project setups with one &lt;code&gt;tsconfig.json&lt;/code&gt;, Nx monorepos can have 50+ configuration files scattered throughout your workspace.&lt;/p&gt;

&lt;p&gt;The challenge is that each project needs its own settings while sharing common configurations. This creates a web of interconnected config files that can feel overwhelming when you're just trying to import a utility function.&lt;/p&gt;

&lt;p&gt;The good news is that Nx handles most of this complexity automatically for you, but understanding how things work under the hood helps you troubleshoot issues and make informed decisions about your workspace structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Configuration Pitfalls
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Treating configs as independent&lt;/strong&gt;: Developers sometimes copy settings between projects, unaware that Nx relies on inheritance, so their changes can unintentionally impact the entire workspace.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Manually editing path mappings&lt;/strong&gt;: Adding paths manually to fix import errors, when Nx auto-generates these mappings based on the workspace structure.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Circular dependencies&lt;/strong&gt;: Creating innocent-looking imports between libraries that later cause dependency cycles with cryptic error messages.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Build vs runtime confusion&lt;/strong&gt;: Setting up configs perfectly for development, then wondering why production builds fail or deployed apps can't resolve modules.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Inheritance Chain Explained
&lt;/h3&gt;

&lt;p&gt;Think of Nx TypeScript configuration like a family tree. At the workspace root, &lt;code&gt;tsconfig.base.json&lt;/code&gt; sets defaults and path mappings that flow down to every project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Base level&lt;/strong&gt;: Workspace-wide settings that all projects inherit&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Project level&lt;/strong&gt;: Each app/library extends the base config with its own specific needs&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Purpose-specific&lt;/strong&gt;: Individual projects often have multiple configs (build, test, type-checking) that extend from their main project config&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you change the base configuration, it affects every project that inherits from it. This is powerful but requires careful thinking about where changes should be made.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Configuration Files
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmayallo.com%2Fwp-content%2Fuploads%2F2025%2F06%2Fnx-monorepo-configurations-1024x683.avif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmayallo.com%2Fwp-content%2Fuploads%2F2025%2F06%2Fnx-monorepo-configurations-1024x683.avif" alt="Understanding the Nx Monorepo Configuration Files" width="1024" height="683"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nx organizes TypeScript configurations for good reason. It wants to make sure different parts of your monorepo can share code and build efficiently. It is very smart about this. Moreover, this organization prevents conflicts and ensures consistency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Root Level &lt;strong&gt;&lt;code&gt;tsconfig.base.json&lt;/code&gt;: The Global Foundation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;&lt;code&gt;tsconfig.base.json&lt;/code&gt;&lt;/strong&gt; file is the cornerstone of your workspace's TypeScript configuration. It's where you define the global settings that will be inherited by all the applications and libraries within your monorepo. This is the place to specify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Common compiler options&lt;/strong&gt;: Settings like &lt;code&gt;target&lt;/code&gt;, &lt;code&gt;module&lt;/code&gt;, &lt;code&gt;strict&lt;/code&gt;, and &lt;code&gt;esModuleInterop&lt;/code&gt; that you want to apply universally.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Path aliases&lt;/strong&gt;: To simplify import statements across your projects, you can define path mappings here. For example, you can map &lt;code&gt;@my-org/my-lib&lt;/code&gt; to the actual path of the library, making it easier to reference shared code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By centralizing these common configurations, you ensure consistency and reduce redundancy across your entire codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Root Level &lt;strong&gt;&lt;code&gt;tsconfig.json&lt;/code&gt;: Enabling Project References&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;More recently, Nx has introduced a root-level &lt;strong&gt;&lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/strong&gt; to leverage &lt;a href="https://www.typescriptlang.org/docs/handbook/project-references.html" rel="noopener noreferrer"&gt;TypeScript project references&lt;/a&gt;. This feature helps to improve build times and enforce clearer boundaries between your projects.&lt;/p&gt;

&lt;p&gt;The primary role of this root &lt;code&gt;tsconfig.json&lt;/code&gt; is to enumerate all the projects (applications and libraries) in your workspace. It contains a &lt;code&gt;references&lt;/code&gt; array that points to the &lt;code&gt;tsconfig.json&lt;/code&gt; file of each individual project.&lt;/p&gt;

&lt;p&gt;This allows TypeScript-aware tools and editors to understand the dependency graph of your monorepo, leading to more efficient compilation and a better development experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Level &lt;strong&gt;&lt;code&gt;tsconfig.json&lt;/code&gt;: The Project Entry Point&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Every project (be it an application or a library) has its own &lt;strong&gt;&lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/strong&gt; file. This file acts as the main configuration entry point for that specific project.&lt;/p&gt;

&lt;p&gt;It typically contains &lt;code&gt;references&lt;/code&gt; to the other specialized &lt;code&gt;tsconfig.*.json&lt;/code&gt; files within the same project directory, such as &lt;code&gt;tsconfig.app.json&lt;/code&gt; or &lt;code&gt;tsconfig.lib.json&lt;/code&gt;, and &lt;code&gt;tsconfig.spec.json&lt;/code&gt;. Or it might include &lt;code&gt;references&lt;/code&gt; to the &lt;code&gt;tsconfig.*.json&lt;/code&gt; files from the other dependent projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Level &lt;strong&gt;&lt;code&gt;tsconfig.app.json&lt;/code&gt; &amp;amp; &lt;code&gt;tsconfig.lib.json&lt;/code&gt;: Application and Library Specifics&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Depending on whether you've generated an application or a library, you will find either a &lt;strong&gt;&lt;code&gt;tsconfig.app.json&lt;/code&gt;&lt;/strong&gt; or a &lt;strong&gt;&lt;code&gt;tsconfig.lib.json&lt;/code&gt;&lt;/strong&gt; file. These files are tailored for the specific needs of their respective project types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;tsconfig.app.json&lt;/code&gt;&lt;/strong&gt;: This file contains TypeScript compiler options that are specific to an application. For instance, it might include settings related to the application's build output or specific environment requirements.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;tsconfig.lib.json&lt;/code&gt;&lt;/strong&gt;: Similarly, this file holds configurations that are particular to a library. This could include settings for generating declaration files (&lt;code&gt;.d.ts&lt;/code&gt;) or other library-focused compiler options.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both of these files extend the root &lt;code&gt;tsconfig.base.json&lt;/code&gt; and can override any of the global settings as needed for that particular project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Level &lt;strong&gt;&lt;code&gt;tsconfig.spec.json&lt;/code&gt;: Fine-Tuning for Tests&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For your test files, Nx generates a &lt;strong&gt;&lt;code&gt;tsconfig.spec.json&lt;/code&gt;&lt;/strong&gt;. This configuration file is specifically designed for your testing environment. It allows you to have a distinct TypeScript setup for your tests, which can be useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Including test-specific files and type definitions.&lt;/li&gt;
&lt;li&gt;  Configuring a different module system or other compiler options that are better suited for your testing framework (like Jest or Vitest).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Like the other project-level &lt;code&gt;tsconfig&lt;/code&gt; files, &lt;code&gt;tsconfig.spec.json&lt;/code&gt; also extends the base configuration, ensuring that your tests are compiled with the necessary settings without affecting your application or library source code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Root Level &lt;strong&gt;&lt;code&gt;nx.json&lt;/code&gt;: The Workspace "Brain"&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;At the root of your workspace, the &lt;strong&gt;&lt;code&gt;nx.json&lt;/code&gt;&lt;/strong&gt; file acts as the central configuration hub or the "brain" for the Nx CLI. While &lt;code&gt;tsconfig.base.json&lt;/code&gt; manages global TypeScript settings, &lt;code&gt;nx.json&lt;/code&gt; manages workspace-wide &lt;em&gt;operational&lt;/em&gt; settings.&lt;/p&gt;

&lt;p&gt;Its key responsibilities include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Task Dependencies:&lt;/strong&gt; Defining the dependency order for tasks. For example, ensuring a library is always built before an application that uses it.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Caching Configuration:&lt;/strong&gt; Specifying which tasks are cacheable. This is a core feature of Nx that saves immense amounts of time by not re-running tasks (like builds or tests) if the source code hasn't changed.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Default Runners and Executors:&lt;/strong&gt; Setting the default tools used to run tasks across your projects.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Plugins and Generators:&lt;/strong&gt; Configuring Nx plugins that extend the workspace's capabilities, like adding support for new frameworks or tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, &lt;code&gt;nx.json&lt;/code&gt; orchestrates how Nx operates on a global level, making your development workflow fast and consistent.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Project Level &lt;code&gt;project.json&lt;/code&gt; or &lt;code&gt;package.json&lt;/code&gt;&lt;/strong&gt;: &lt;strong&gt;The Project's Instruction Manual&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Inside each application and library folder, you'll find a file that serves as the instruction manual for that specific project. This configuration tells Nx everything it needs to know about the project, most importantly, what "targets" it has. A target is simply a task that you can run, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;build&lt;/code&gt;&lt;/strong&gt;: To compile the application or library.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;test&lt;/code&gt;&lt;/strong&gt;: To execute unit tests.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;lint&lt;/code&gt;&lt;/strong&gt;: To check for code style and errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This configuration can be defined in one of two ways. One approach is a dedicated &lt;strong&gt;&lt;code&gt;project.json&lt;/code&gt;&lt;/strong&gt; file. Alternatively, the configuration can live inside the project's &lt;strong&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/strong&gt; file, under a special &lt;code&gt;"nx": {}&lt;/code&gt; property. Both methods achieve the same goal and are valid ways to configure a project in a workspace.&lt;/p&gt;

&lt;p&gt;For each target, the configuration defines the &lt;strong&gt;executor&lt;/strong&gt; (the tool that runs the task, like Webpack or Jest) and any specific options that tool needs to operate on that project.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Nx's Superpower: Inferring Tasks Automatically&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Here is where Nx truly shines. While you can explicitly define every task for every project, you often don't have to. Nx has the powerful ability to &lt;strong&gt;infer tasks&lt;/strong&gt; automatically by detecting the presence of tool-specific configuration files.&lt;/p&gt;

&lt;p&gt;For example, if you add a &lt;code&gt;jest.config.ts&lt;/code&gt; file to your project, Nx will see it and automatically create a &lt;code&gt;test&lt;/code&gt; target for you behind the scenes. If you add an &lt;code&gt;.eslintrc.json&lt;/code&gt; file, a &lt;code&gt;lint&lt;/code&gt; target is instantly made available. This works for a wide range of common development tools.&lt;/p&gt;

&lt;p&gt;This inference capability is a key advantage, as it dramatically reduces boilerplate configuration and keeps your &lt;code&gt;project.json&lt;/code&gt; files lean. You only need to manually define targets when you have a complex setup or need to override the inferred behavior. It’s a smart system that provides structure when you need it and gets out of your way when you don't.&lt;/p&gt;

&lt;p&gt;[newsletter_form form="2"]&lt;/p&gt;

&lt;h2&gt;
  
  
  Path Aliases vs. Project References: Which Should You Choose?
&lt;/h2&gt;

&lt;p&gt;This is a common question in Nx and TypeScript in general. Both path aliases and project references help you organize imports. However, they do it in very different ways, and have different benefits.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are Path Aliases?
&lt;/h3&gt;

&lt;p&gt;Path aliases let you create shortcuts for import paths. Instead of a long relative path like &lt;code&gt;../../../libs/my-lib/src&lt;/code&gt;, you can use &lt;code&gt;@my-org/my-lib&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This makes your import statements much cleaner and easier to read. I always use them; they really improve code readability. They're like giving your home a nickname instead of saying its full address every time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before Path Alias&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;Button&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;../../../../packages/shared-ui/src/lib/shared-ui&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// This path is long and hard to read.&lt;/span&gt;

&lt;span class="c1"&gt;// After Path Alias (defined in tsconfig.base.json)&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;Button&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;@my-awesome-nx-repo/shared-ui&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// This is much shorter and clearer, thanks to the alias.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Pros:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Cleaner import statements.&lt;/li&gt;
&lt;li&gt;  Easier to move files around without updating import paths.&lt;/li&gt;
&lt;li&gt;  Works well for smaller monorepos or just for readability.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Cons:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  TypeScript treats them as simple text replacements; no strong compile-time checks for module existence.&lt;/li&gt;
&lt;li&gt;  Might not leverage Nx's caching as effectively for builds.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  What are TypeScript Project References?
&lt;/h3&gt;

&lt;p&gt;TypeScript Project References are a more robust way to link projects. They allow TypeScript to understand the dependencies between different projects. This means TypeScript can check types across project boundaries. Also, it only recompiles changed projects, which saves a lot of time. This is a game-changer for large monorepos.&lt;/p&gt;

&lt;p&gt;To use project references, you add a &lt;code&gt;references&lt;/code&gt; array to your &lt;code&gt;tsconfig.json&lt;/code&gt; files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;apps/my-react-app/tsconfig.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;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"../../tsconfig.base.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;"files"&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;"include"&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;"references"&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;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"../../packages/shared-ui"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;links&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'shared-ui'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;project.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TypeScript&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;will&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;understand&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;project's&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;types&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;changes.&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Pros:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Improved build performance through incremental builds.&lt;/li&gt;
&lt;li&gt;  Stronger type checking across projects.&lt;/li&gt;
&lt;li&gt;  Better IDE support for navigation and refactoring.&lt;/li&gt;
&lt;li&gt;  Essential for very large workspaces, as Nx's build system uses these for the dependency graph.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Cons:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Can be more complex to set up initially.&lt;/li&gt;
&lt;li&gt;  Requires all referenced projects to also be TypeScript projects.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Verdict: Path Aliases vs. Project References
&lt;/h3&gt;

&lt;p&gt;For small projects or just for making imports pretty, &lt;strong&gt;path aliases&lt;/strong&gt; are fine. However, for most Nx monorepos, especially bigger ones, you should definitely use &lt;strong&gt;TypeScript Project References&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Nx itself heavily relies on them for its build system and caching. It’s the expert choice for performance and type safety.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting Common TypeScript Issues
&lt;/h2&gt;

&lt;p&gt;Even with a good setup, you might face issues. I've spent countless hours debugging weird TypeScript errors in Nx. Here are some common problems and how to fix them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Import Resolution Problems
&lt;/h3&gt;

&lt;p&gt;One of the most common issues is TypeScript not being able to find your imports. This usually looks like: &lt;code&gt;"Cannot find module '@my-org/my-lib' or its corresponding type declarations."&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Possible Causes and Solutions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Incorrect &lt;code&gt;paths&lt;/code&gt; in &lt;code&gt;tsconfig.base.json&lt;/code&gt;&lt;/strong&gt;: Double-check your path aliases. Make sure the path actually points to the &lt;code&gt;src/index.ts&lt;/code&gt; of your library.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Check&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;part&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;carefully&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"paths"&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;"@my-org/my-lib"&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;"libs/my-lib/src/index.ts"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ensure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;correctly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;points&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;library's&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;entry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;file.&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;ul&gt;
&lt;li&gt;  &lt;strong&gt;Missing Project Reference&lt;/strong&gt;: If you're using project references, ensure the &lt;code&gt;references&lt;/code&gt; array in the consumer project's &lt;code&gt;tsconfig.json&lt;/code&gt; correctly lists the library.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;apps/my-react-app/tsconfig.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"references"&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;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"../../packages/shared-ui"&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="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Verify&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;referenced&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;library&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;accurate.&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;ul&gt;
&lt;li&gt;  &lt;strong&gt;Caching Issues&lt;/strong&gt;: Sometimes Nx's cache can get stale. A simple &lt;code&gt;nx reset&lt;/code&gt; or &lt;code&gt;rm -rf node_modules dist .nx/cache&lt;/code&gt; followed by &lt;code&gt;npm install&lt;/code&gt; (or &lt;code&gt;yarn&lt;/code&gt;) and &lt;code&gt;nx build &amp;lt;project-name&amp;gt;&lt;/code&gt; often solves it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Build Errors and Solutions
&lt;/h3&gt;

&lt;p&gt;Sometimes TypeScript compiles fine, but Nx build commands fail. Or you get runtime errors related to types.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Compiler Errors&lt;/strong&gt;: Check your &lt;code&gt;tsconfig.app.json&lt;/code&gt; or &lt;code&gt;tsconfig.lib.json&lt;/code&gt; files. Are your &lt;code&gt;include&lt;/code&gt; and &lt;code&gt;exclude&lt;/code&gt; arrays correct? Sometimes a test file gets included in a build.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ensure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;are&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;excluded&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;build&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"exclude"&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;"jest.config.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/**/*.test.ts"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Prevents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;test-related&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;being&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;bundled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;production&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;build.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Version Mismatches&lt;/strong&gt;: Ensure your TypeScript version is consistent across your workspace. Using different versions can cause strange issues. Check your &lt;code&gt;package.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Circular Dependencies&lt;/strong&gt;: If project A depends on project B, and B depends on A, TypeScript (and Nx) will struggle. Nx helps detect this, but it's best to fix the code structure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  IDE Integration Issues
&lt;/h3&gt;

&lt;p&gt;Your IDE (like VS Code) uses &lt;code&gt;tsconfig.json&lt;/code&gt; files to give you autocompletion and error hints. If your IDE isn't working correctly, it's often a configuration problem.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Restart IDE&lt;/strong&gt;: The simplest fix. Close and reopen VS Code.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Workspace &lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/strong&gt;: Make sure the root &lt;code&gt;tsconfig.json&lt;/code&gt; correctly references all projects. This is what your IDE uses to get a global view.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Nx Console extension&lt;/strong&gt;: If you're using VS Code, install the &lt;a href="https://marketplace.visualstudio.com/items?itemName=nrwl.angular-console" rel="noopener noreferrer"&gt;Nx Console extension&lt;/a&gt;. It helps a lot with understanding and managing Nx projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Caching and Performance in Nx
&lt;/h2&gt;

&lt;p&gt;Nx is famous for its performance, and caching is a big part of that. Understanding how it works with TypeScript projects can significantly speed up your development.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Nx Caching Works
&lt;/h3&gt;

&lt;p&gt;Nx uses a computation cache. When you run a command (like &lt;code&gt;nx build my-app&lt;/code&gt;), Nx first checks if it has already built that project with the same &lt;strong&gt;inputs&lt;/strong&gt;. If yes, it just restores the &lt;strong&gt;output&lt;/strong&gt; from its cache instead of running the build again. This includes source files, &lt;code&gt;package.json&lt;/code&gt; dependencies, &lt;code&gt;tsconfig&lt;/code&gt; files, and even environment variables. It saves so much time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Inputs&lt;/strong&gt;: The files and configurations that define a task's output.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Outputs&lt;/strong&gt;: The generated files (e.g., &lt;code&gt;dist&lt;/code&gt; folder).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Hashing&lt;/strong&gt;: Nx computes a hash of all inputs. If the hash hasn't changed, the output is pulled from cache.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To check what Nx is caching:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nx show cache &lt;span class="c"&gt;# Displays general information about the Nx cache.&lt;/span&gt;
nx graph &lt;span class="nt"&gt;--files-json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="c"&gt;# Generates a JSON representation of the dependency graph, which influences caching decisions.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Performance Tuning Your TypeScript Project
&lt;/h3&gt;

&lt;p&gt;You can optimize your Nx TypeScript projects for even better performance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Leverage Project References&lt;/strong&gt;: As discussed, project references enable incremental builds, where only affected projects are recompiled. This is a huge performance gain.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Correct &lt;code&gt;include&lt;/code&gt;/&lt;code&gt;exclude&lt;/code&gt;&lt;/strong&gt;: Don't include unnecessary files in your &lt;code&gt;tsconfig&lt;/code&gt; files. For example, don't include test files in your main build configuration.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Optimize &lt;code&gt;compilerOptions&lt;/code&gt;&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;skipLibCheck: true&lt;/code&gt;: Speeds up compilation by skipping type checking of declaration files from &lt;code&gt;node_modules&lt;/code&gt;. Most times, this is safe to use.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;isolatedModules: true&lt;/code&gt;: Ensures every file can be compiled independently, which is good for tools like Babel.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Clean &lt;code&gt;node_modules&lt;/code&gt;&lt;/strong&gt;: Occasionally clear your &lt;code&gt;node_modules&lt;/code&gt; and reinstall. Sometimes old packages or faulty caches can slow things down.&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Use the Daemon&lt;/strong&gt;: Nx Daemon runs in the background and keeps a dependency graph in memory, making subsequent commands faster. It's usually on by default.
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;nx.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ensure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;caching&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enabled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;targets&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;"tasksRunnerOptions"&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;"default"&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;"runner"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nx/tasks-runners/default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"options"&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;"cacheableOperations"&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;"build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"e2e"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Explicitly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;marks&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;these&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tasks&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;cacheable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;so&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;will&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;store&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;their&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;outputs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;faster&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;re-execution.&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="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;ul&gt;
&lt;li&gt;  &lt;code&gt;cacheableOperations&lt;/code&gt;: Lists which tasks Nx should try to cache.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Nx TypeScript configuration might seem daunting at first, but once you understand the inheritance pattern and common pitfalls, it becomes much more manageable. Remember that Nx does the heavy lifting automatically - your job is simply to understand the system well enough to troubleshoot when things go wrong and make informed decisions about your workspace structure.&lt;/p&gt;

&lt;p&gt;The key is starting simple and gradually building complexity as your monorepo grows. With these fundamentals in place, you'll spend less time fighting configuration issues and more time building great applications.&lt;/p&gt;

&lt;p&gt;If you want to dive deeper, have a look at these resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://nx.dev/blog/typescript-project-references" rel="noopener noreferrer"&gt;Everything You Need to Know About TypeScript Project References&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://nx.dev/concepts/typescript-project-linking" rel="noopener noreferrer"&gt;Typescript Project Linking&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://nx.dev/reference/project-configuration" rel="noopener noreferrer"&gt;Project Configuration&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://nx.dev/concepts/types-of-configuration" rel="noopener noreferrer"&gt;Managing Configuration Files&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Think about it
&lt;/h2&gt;

&lt;p&gt;If you enjoyed this article, I’d truly appreciate it if you could share it—it really motivates me to keep creating more helpful content!&lt;/p&gt;

&lt;p&gt;If you’re interested in exploring more, check out these articles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/nx-monorepo-nodejs-react/" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://mayallo.com/nx-monorepo-nodejs-react/" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://mayallo.com/nx-monorepo-nodejs-react/" rel="noopener noreferrer"&gt;Nx Monorepo Guide: React &amp;amp; Node Fullstack App&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/typescript-type-vs-interface/" rel="noopener noreferrer"&gt;TypeScript Type vs Interface? The Answer Is Type!&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/typescript-omit-multiple-keys/" rel="noopener noreferrer"&gt;How to Omit Multiple Keys in TypeScript&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/overloading-vs-overriding-typescript/" rel="noopener noreferrer"&gt;Overloading vs. Overriding in TypeScript&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for sticking with me until the end—I hope you found this article valuable and enjoyable!&lt;/p&gt;

</description>
      <category>monorepo</category>
      <category>nx</category>
      <category>typescript</category>
      <category>programming</category>
    </item>
    <item>
      <title>SQL COALESCE in Postgres: A Simple Guide</title>
      <dc:creator>Mohamed Mayallo</dc:creator>
      <pubDate>Mon, 09 Jun 2025 16:15:11 +0000</pubDate>
      <link>https://dev.to/mayallo/sql-coalesce-in-postgres-a-simple-guide-48nl</link>
      <guid>https://dev.to/mayallo/sql-coalesce-in-postgres-a-simple-guide-48nl</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In a database, we often find empty places in our tables. These are not zeros or spaces; they are special markers called &lt;code&gt;NULL&lt;/code&gt;. A &lt;code&gt;NULL&lt;/code&gt; value means "no data." This can be a problem.&lt;/p&gt;

&lt;p&gt;Let's see how the SQL COALESCE function can help us solve this common issue using Postgres examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Small Shop Example
&lt;/h2&gt;

&lt;p&gt;Imagine you have a small online shop. You have a table in your database called &lt;code&gt;products&lt;/code&gt;. This table stores information about your products, like their name, their normal price, and a special discount price.&lt;/p&gt;

&lt;p&gt;First, let's create our &lt;code&gt;products&lt;/code&gt; table.&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="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;product_name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&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;regular_price&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;discount_price&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&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;Now, let's add some data to our table. Notice that some products have a &lt;code&gt;discount_price&lt;/code&gt; and some do not (their &lt;code&gt;discount_price&lt;/code&gt; is &lt;code&gt;NULL&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="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regular_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;discount_price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Cool T-Shirt'&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="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Jeans'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;,&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="s1"&gt;'Hat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Socks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our table is ready. We have some products with discounts and some without.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with NULL
&lt;/h2&gt;

&lt;p&gt;Let's say you want to show your customers the final price. If a product has a discount, you show the &lt;code&gt;discount_price&lt;/code&gt;. If it does not, you show the &lt;code&gt;regular_price&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You might try to select the &lt;code&gt;discount_price&lt;/code&gt; like this:&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;SELECT&lt;/span&gt; &lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;discount_price&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result will look like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;product_name&lt;/th&gt;
&lt;th&gt;discount_price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cool T-Shirt&lt;/td&gt;
&lt;td&gt;15.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jeans&lt;/td&gt;
&lt;td&gt;&lt;em&gt;NULL&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hat&lt;/td&gt;
&lt;td&gt;12.50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Socks&lt;/td&gt;
&lt;td&gt;&lt;em&gt;NULL&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is a problem. You cannot show "NULL" to your customers on your website. They will be confused. You need to show the &lt;code&gt;regular_price&lt;/code&gt; when the &lt;code&gt;discount_price&lt;/code&gt; is &lt;code&gt;NULL&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A First Try: The CASE Statement
&lt;/h2&gt;

&lt;p&gt;One way to solve this is using a &lt;code&gt;CASE&lt;/code&gt; statement. The &lt;code&gt;CASE&lt;/code&gt; statement goes through conditions and returns a value when the first condition is met.&lt;/p&gt;

&lt;p&gt;Here is how you can use &lt;code&gt;CASE&lt;/code&gt; to show the correct price:&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;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;CASE&lt;/span&gt;
        &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;discount_price&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="n"&gt;discount_price&lt;/span&gt;
        &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="n"&gt;regular_price&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;final_price&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This query says: check the &lt;code&gt;discount_price&lt;/code&gt;. If it is not &lt;code&gt;NULL&lt;/code&gt;, then use it. If it is &lt;code&gt;NULL&lt;/code&gt;, then use the &lt;code&gt;regular_price&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This works! The result is:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;product_name&lt;/th&gt;
&lt;th&gt;final_price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cool T-Shirt&lt;/td&gt;
&lt;td&gt;15.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jeans&lt;/td&gt;
&lt;td&gt;50.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hat&lt;/td&gt;
&lt;td&gt;12.50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Socks&lt;/td&gt;
&lt;td&gt;8.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;But the &lt;code&gt;CASE&lt;/code&gt; statement can be long to write, especially if you have many conditions. This brings us to a better way. When we compare &lt;strong&gt;PostgreSQL Coalesce vs Case&lt;/strong&gt;, we see that &lt;code&gt;COALESCE&lt;/code&gt; is much simpler for this task.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Best Solution: The COALESCE Function
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;COALESCE&lt;/code&gt; function in PostgreSQL is a perfect and simple solution for this problem. It returns the first non-&lt;code&gt;NULL&lt;/code&gt; value from a list of arguments.&lt;/p&gt;

&lt;p&gt;The syntax is very easy: &lt;code&gt;COALESCE(argument_1, argument_2, ...)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let's write our query again, but this time using &lt;code&gt;COALESCE&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="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;COALESCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;discount_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regular_price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;final_price&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This query does the same thing as the &lt;code&gt;CASE&lt;/code&gt; statement. It looks at &lt;code&gt;discount_price&lt;/code&gt; first. If &lt;code&gt;discount_price&lt;/code&gt; is not &lt;code&gt;NULL&lt;/code&gt;, it returns that value. If it is &lt;code&gt;NULL&lt;/code&gt;, it moves to the next argument, which is &lt;code&gt;regular_price&lt;/code&gt;, and returns that value.&lt;/p&gt;

&lt;p&gt;The result is exactly the same, but the query is much shorter and easier to read.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;product_name&lt;/th&gt;
&lt;th&gt;final_price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cool T-Shirt&lt;/td&gt;
&lt;td&gt;15.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jeans&lt;/td&gt;
&lt;td&gt;50.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hat&lt;/td&gt;
&lt;td&gt;12.50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Socks&lt;/td&gt;
&lt;td&gt;8.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Using COALESCE with Many Values
&lt;/h2&gt;

&lt;p&gt;The power of &lt;code&gt;COALESCE&lt;/code&gt; does not stop there. You can use it with many values. This is helpful when you need to &lt;strong&gt;coalesce multiple columns&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let's add a new column to our table called &lt;code&gt;clearance_price&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="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;clearance_price&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;clearance_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;product_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Cool T-Shirt'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the T-Shirt has a &lt;code&gt;regular_price&lt;/code&gt;, a &lt;code&gt;discount_price&lt;/code&gt;, and a &lt;code&gt;clearance_price&lt;/code&gt;. We want to show the &lt;code&gt;clearance_price&lt;/code&gt; if it exists. If not, the &lt;code&gt;discount_price&lt;/code&gt; if it exists. If not, then the &lt;code&gt;regular_price&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;COALESCE&lt;/code&gt; makes this very easy.&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;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;COALESCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clearance_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;discount_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regular_price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;final_price&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function will check each column in order (&lt;code&gt;clearance_price&lt;/code&gt;, then &lt;code&gt;discount_price&lt;/code&gt;, then &lt;code&gt;regular_price&lt;/code&gt;) and return the very first price that is not &lt;code&gt;NULL&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The SQL &lt;code&gt;COALESCE&lt;/code&gt; function is a powerful tool in PostgreSQL. It helps you write clean, simple, and readable SQL. When you need to replace &lt;code&gt;NULL&lt;/code&gt; with a default value, &lt;code&gt;COALESCE&lt;/code&gt; is often the best choice.&lt;/p&gt;

&lt;p&gt;It is simpler than writing long &lt;code&gt;CASE&lt;/code&gt; statements and makes your code better. So next time you have a problem with &lt;code&gt;NULL&lt;/code&gt; values, remember the SQL COALESCE function.&lt;/p&gt;

&lt;p&gt;Finally, if you found this article useful, you can check more here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/inner-join-3-tables-sql/" rel="noopener noreferrer"&gt;How to Inner Join 3 Tables in SQL&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/facade-vs-proxy-vs-adapter-design-patterns/" rel="noopener noreferrer"&gt;Facade vs Proxy vs Adapter Design Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/typescript-type-vs-interface/" rel="noopener noreferrer"&gt;TypeScript Type Vs Interface? The Answer Is Type!&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>sql</category>
      <category>postgres</category>
      <category>database</category>
      <category>programming</category>
    </item>
    <item>
      <title>Nx Monorepo Guide: React &amp; Node Fullstack App</title>
      <dc:creator>Mohamed Mayallo</dc:creator>
      <pubDate>Thu, 05 Jun 2025 07:00:00 +0000</pubDate>
      <link>https://dev.to/mayallo/nx-monorepo-guide-react-node-fullstack-app-1bhe</link>
      <guid>https://dev.to/mayallo/nx-monorepo-guide-react-node-fullstack-app-1bhe</guid>
      <description>&lt;h2&gt;
  
  
  What is a Monorepo and Why Nx?
&lt;/h2&gt;

&lt;p&gt;Ever find yourself checking many projects, each in its own GitHub repo, making updates feel like fixing one thing just makes another pop up? I know I used to.&lt;/p&gt;

&lt;p&gt;It's often difficult to keep track of all the different versions of things or remember where that one shared piece of code actually lived. This scattered setup really tests your patience, doesn't it? Well, there's another way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding Monorepo Architecture
&lt;/h3&gt;

&lt;p&gt;A monorepo holds all code for many projects in one single version control repository. All the different parts of a big system, like a website, an API, or even a mobile app, live side-by-side. For example, Google, Facebook, and Microsoft all use monorepos for parts of their massive codebases. This approach can really speed up things.&lt;/p&gt;

&lt;p&gt;Consider a shared component library. In a traditional setup, you'd publish it to npm, then each project would install it. With a monorepo, you just import it directly, no publishing needed. This removes so much friction! However, managing changes across many projects in one place needs special tools. Otherwise, it becomes a mess, this is where Nx shines.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Makes Nx Special for Developers
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Smart monorepo tool&lt;/strong&gt;: Nx is more than just a basic tool; it’s designed for managing monorepos, especially for JavaScript and TypeScript projects.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Understands project structure&lt;/strong&gt;: Nx maps out how your projects are connected and knows exactly what needs to be rebuilt when you make even a small change.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Saves time and resources&lt;/strong&gt;: By rebuilding only what’s necessary, Nx speeds up builds and testing, saving time and computing power.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Computation caching&lt;/strong&gt;: Nx remembers tasks (like builds or tests) it has already done; if the code hasn’t changed, it skips the task and uses cached results instead.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Built-in code generators and plugins&lt;/strong&gt;: Supports popular tools like React, Angular, Node.js, and Jest, which helps keep code clean, consistent, and easy to maintain across your entire project.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Supports clean testing setup&lt;/strong&gt;: Nx makes it easier to set up and manage your testing framework.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Nx vs Other Monorepo Tools Comparison
&lt;/h2&gt;

&lt;p&gt;Many tools support monorepos, but they offer different levels of functionality. Here's how Nx compares to some of the most popular options.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nx vs Lerna
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://lerna.js.org/" rel="noopener noreferrer"&gt;Lerna&lt;/a&gt; was one of the first monorepo tools, focusing on managing and publishing packages. Nx goes much further by including a full build system and more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key differences:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Build system:&lt;/strong&gt; Nx includes smart task orchestration and caching; Lerna does not.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Code generation:&lt;/strong&gt; Built into Nx; not available in Lerna.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Dependency graph:&lt;/strong&gt; Nx understands task relationships; Lerna tracks only package dependencies.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Plugin ecosystem:&lt;/strong&gt; Nx supports many frameworks and tools; Lerna is limited to package-related tasks.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;CI/CD integration:&lt;/strong&gt; Nx has built-in support for affected-only commands; Lerna needs manual setup.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Development activity:&lt;/strong&gt; Nx is actively maintained and growing; Lerna is stable but less active.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; Nx is an all-in-one solution, while Lerna often requires other tools to match the same functionality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nx vs Turborepo
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://turborepo.com/" rel="noopener noreferrer"&gt;Turborepo&lt;/a&gt; is known for its speed, especially with caching and parallel task execution. Nx offers similar performance but provides a broader developer experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key differences:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Focus:&lt;/strong&gt; Turborepo is minimal and fast; Nx is full-featured and flexible.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Tooling:&lt;/strong&gt; Nx includes code scaffolding, plugins, and workspace generators; Turborepo does not.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Use case:&lt;/strong&gt; Turborepo is great if you already have a strong setup; Nx helps guide structure from the start.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; Turborepo is like a high-speed engine; Nx is a full vehicle ready for production use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nx vs npm Workspaces
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.npmjs.com/cli/v7/using-npm/workspaces/" rel="noopener noreferrer"&gt;npm Workspaces&lt;/a&gt; help link local packages inside a monorepo, letting you manage dependencies across projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key differences:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Scope:&lt;/strong&gt; npm Workspaces handle package linking only; Nx adds intelligent build orchestration and caching.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Features:&lt;/strong&gt; Nx provides code generation, task execution, dependency graphs, and CI optimizations—none of which are part of npm Workspaces.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Integration:&lt;/strong&gt; Nx works with npm Workspaces (and pnpm/Yarn) as a base, then builds on top of them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; npm Workspaces handle the basics; Nx turns that foundation into a powerful monorepo platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Your First Nx Workspace
&lt;/h2&gt;

&lt;p&gt;Ready to get your hands dirty? Setting up an Nx workspace isn't hard, I promise. It's a quick process to get a powerful development environment ready. You'll soon see how easy it is to manage different apps and libs in one place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Please find the complete code &lt;a href="https://github.com/Mohamed-Mayallo/my-awesome-nx-repo" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Your Nx Workspace with CLI
&lt;/h3&gt;

&lt;p&gt;Now, let's create our first Nx Monorepo. It's done with a single command. Open your terminal or command prompt and type this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-nx-workspace@latest my-awesome-nx-repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;npx&lt;/code&gt;: This runs the &lt;code&gt;create-nx-workspace&lt;/code&gt; package without installing it globally.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;create-nx-workspace@latest&lt;/code&gt;: Ensures you get the most recent version of the Nx workspace generator.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;my-awesome-nx-repo&lt;/code&gt;: This is the name of your new workspace folder. You can name it whatever you like.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you run this, Nx will ask you a few questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;"Need to install the following packages: create-nx-workspace"&lt;/strong&gt;: Yes, if you want to install it globally.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;"&lt;/strong&gt;Which stack*&lt;em&gt;?"&lt;/em&gt;*: None, will set up each app individually.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;"Prettier for code formatting?"&lt;/strong&gt; Yes.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;"Which CI provider?"&lt;/strong&gt;: Do it later.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;"Remote caching using Nx Cloud?"&lt;/strong&gt;: No.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After this, Nx will install everything. It takes a minute or two. You now have a working Nx workspace! Go into the folder: &lt;code&gt;cd my-awesome-nx-repo&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Essential Nx Configuration Files Explained
&lt;/h3&gt;

&lt;p&gt;Nx uses a few main configuration files to know how to build, test, and lint your projects. Understanding these files helps you work better with Nx.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;nx.json&lt;/code&gt;&lt;/strong&gt;: This is the heart of your Nx workspace configuration. It defines projects, their types (application or library), and how they relate to each other. It also sets up caching strategies and task runners.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/strong&gt;: This file, at the root of your workspace, lists all the global dependencies for your entire monorepo. Instead of each app having its own &lt;code&gt;node_modules&lt;/code&gt;, Nx (via Yarn/pnpm/npm workspaces) often hoists them to the root.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;tsconfig.base.json&lt;/code&gt;&lt;/strong&gt;: This is the top-level TypeScript configuration. It defines common settings for all TypeScript projects in your workspace. Keep in mind, every project has its own &lt;code&gt;tsconfig&lt;/code&gt; file to override this top configuration file.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/strong&gt;: Acts as the project references entry point for TypeScript in a monorepo. Its &lt;code&gt;references&lt;/code&gt; value lists all apps and libs, so TypeScript understands the project graph and can do incremental builds.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Nx CLI Commands Every Developer Should Know
&lt;/h3&gt;

&lt;p&gt;Nx uses a command line interface (CLI) to manage your workspace. These commands are your daily tools for working with Nx.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;nx generate [generator]&lt;/code&gt; or &lt;code&gt;nx g [generator]&lt;/code&gt;: Creates new applications, libraries, components, etc.

&lt;ul&gt;
&lt;li&gt;  Example: &lt;code&gt;nx g @nx/react:app my-new-react-app&lt;/code&gt; (creates a new React app)&lt;/li&gt;
&lt;li&gt;  Example: &lt;code&gt;nx g @nx/js:lib shared-data&lt;/code&gt; (creates a new JavaScript/TypeScript library)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;code&gt;nx serve [project-name]&lt;/code&gt;: Starts the development server for a specific application.

&lt;ul&gt;
&lt;li&gt;  Example: &lt;code&gt;nx serve my-react-app&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;code&gt;nx build [project-name]&lt;/code&gt;: Builds a project for production.

&lt;ul&gt;
&lt;li&gt;  Example: &lt;code&gt;nx build my-express-api&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;code&gt;nx test [project-name]&lt;/code&gt;: Runs tests for a project.

&lt;ul&gt;
&lt;li&gt;  Example: &lt;code&gt;nx test my-react-app&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;code&gt;nx lint [project-name]&lt;/code&gt;: Runs linting checks for a project.

&lt;ul&gt;
&lt;li&gt;  Example: &lt;code&gt;nx lint shared-ui&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;code&gt;nx graph&lt;/code&gt;: Visualizes the dependency graph of your workspace in your browser. This is super cool and really helps you understand how things connect.&lt;/li&gt;

&lt;li&gt;  &lt;code&gt;nx affected:[command]&lt;/code&gt;: Runs a command only on projects that have changed since your last commit (or a specific commit). This is where Nx's intelligence truly shines for CI/CD.

&lt;ul&gt;
&lt;li&gt;  Example: &lt;code&gt;nx affected:build&lt;/code&gt; (builds only changed projects)&lt;/li&gt;
&lt;li&gt;  Example: &lt;code&gt;nx affected:test&lt;/code&gt; (tests only changed projects)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;These commands, especially &lt;code&gt;nx affected&lt;/code&gt;, are why large monorepos with Nx can still have fast CI pipelines. You only build and test the parts that are truly impacted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you are using VS Code, there is a very handy extension that will make your life way easier; it is &lt;a href="https://marketplace.visualstudio.com/items?itemName=nrwl.angular-console" rel="noopener noreferrer"&gt;&lt;strong&gt;Nx Console&lt;/strong&gt;&lt;/a&gt;; believe me, you will like it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Your First Node.js Backend App
&lt;/h2&gt;

&lt;p&gt;Now that we have a workspace, let's add a Node.js backend. This is often the first step for a lot of web applications. You'll see how easy it is to add new parts to your Nx Monorepo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating a Node.js Application
&lt;/h3&gt;

&lt;p&gt;We can generate a new Node.js application using the Nx CLI. This will create a basic Express.js app for us. It sets up all the boilerplate, so you don't have to. It's truly a time saver.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i @nx/node &lt;span class="nt"&gt;-D&lt;/span&gt;  &lt;span class="c"&gt;# Install the needed plugin&lt;/span&gt;
npx nx generate @nx/node:app packages/my-backend &lt;span class="nt"&gt;--framework&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;express &lt;span class="c"&gt;# Setup our backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;@nx/node:app&lt;/code&gt;: This is the generator for creating Node.js applications.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;packages/my-backend&lt;/code&gt;: The name of your new Node.js application inside the &lt;code&gt;packages&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;--framework=express&lt;/code&gt;: Tells Nx to set up the app using the Express.js framework. You could also choose &lt;code&gt;nest&lt;/code&gt; or &lt;code&gt;none&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nx will add a new folder inside &lt;code&gt;packages/&lt;/code&gt; named &lt;code&gt;my-backend&lt;/code&gt;, complete with a basic &lt;code&gt;src/&lt;/code&gt; directory and setup files. It also adds a new entry in &lt;code&gt;packages.json&lt;/code&gt; workspaces for &lt;code&gt;my-backend&lt;/code&gt; (or you will find &lt;code&gt;"packages/*"&lt;/code&gt;) and updates &lt;code&gt;tsconfig.json&lt;/code&gt; with a path reference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You can list the available plugins using this command &lt;code&gt;nx list&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding the App Structure
&lt;/h3&gt;

&lt;p&gt;Inside &lt;code&gt;packages/my-backend&lt;/code&gt;, you'll find a simple Express app structure. It's designed to be clean and extensible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;packages/my-backend/
├── src/&lt;span class="k"&gt;*&lt;/span&gt;
├── package.json
├── .spec.swcrc
├── tsconfig.json
├── tsconfig.app.json
└── tsconfig.spec.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;src/&lt;/code&gt;&lt;/strong&gt;: Your main app.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/strong&gt;: The &lt;code&gt;"nx": { "targets": { … } }&lt;/code&gt; section in &lt;code&gt;package.json&lt;/code&gt; allows you to define, configure, and customize the various tasks (targets) related to your Node.js app. This is key for automating workflows like building, testing, serving, and linting within an Nx workspace.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;.spec.swcrc&lt;/code&gt;&lt;/strong&gt;: The configuration file used by SWC to optimize and configure the transpilation of your test files during unit tests.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/strong&gt;: Base TypeScript configuration for the app (common settings for all files in the app).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;tsconfig.app.json&lt;/code&gt;&lt;/strong&gt;: TypeScript configuration specifically for compiling the app's source code (src/*.ts).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;tsconfig.spec.json&lt;/code&gt;&lt;/strong&gt;: TypeScript configuration for compiling the app’s test files (src/*.spec.ts).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Mostly, you will find these files in all of your newly generated applications or libraries.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up Basic Express Server
&lt;/h3&gt;

&lt;p&gt;Nx already generates a basic Express server for you. To run it, simply use: &lt;code&gt;npx nx serve my-backend&lt;/code&gt;. You'll see the server start up and listen on &lt;code&gt;http://localhost:3000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you navigate there in your browser, you should see the "Hello API" message. Pretty neat, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding React Components to Your Monorepo
&lt;/h2&gt;

&lt;p&gt;What about adding a frontend? Nx makes it just as easy to add React applications and shared React components. This is where the true power of a monorepo starts to show itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Shared React Library
&lt;/h3&gt;

&lt;p&gt;Let's make a shared library for our React components. This library will live in &lt;code&gt;libs/&lt;/code&gt; and can be used by any React application in our monorepo. It’s like building a reusable Lego set that many different structures can use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i @nx/react &lt;span class="nt"&gt;-D&lt;/span&gt;  &lt;span class="c"&gt;# Install the needed plugin&lt;/span&gt;
npx nx generate @nx/react:lib libs/shared-ui &lt;span class="nt"&gt;--style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;@nx/react:lib&lt;/code&gt;: This generator creates a React library.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;shared-ui&lt;/code&gt;: The name of our new library in the &lt;code&gt;libs&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;--style=css&lt;/code&gt;: Specifies CSS as the styling approach. You could choose &lt;code&gt;scss&lt;/code&gt;, &lt;code&gt;less&lt;/code&gt;, or &lt;code&gt;styled-components&lt;/code&gt; too.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nx creates &lt;code&gt;libs/shared-ui&lt;/code&gt; with a basic component, tests, and its own configuration files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building Your First Reusable Component
&lt;/h3&gt;

&lt;p&gt;Inside &lt;code&gt;libs/shared-ui/src/lib/&lt;/code&gt; you'll find a &lt;code&gt;shared-ui.tsx&lt;/code&gt; file (or similar, depending on Nx version). Let's modify it to be a simple &lt;code&gt;Button&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* libs/shared-ui/src/lib/shared-ui.tsx */&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&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;./shared-ui.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Assuming you have a CSS module&lt;/span&gt;

&lt;span class="cm"&gt;/* eslint-disable-next-line */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text&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="nl"&gt;onClick&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;void&lt;/span&gt;&lt;span class="p"&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;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&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="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Render a button */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Display button text */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Export for easier import&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a simple CSS file to go with it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* libs/shared-ui/src/lib/shared-ui.module.css */&lt;/span&gt;
&lt;span class="nc"&gt;.my-button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="m"&gt;15px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.my-button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.8&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;Now, other projects can use this &lt;code&gt;Button&lt;/code&gt; component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating A New React App
&lt;/h3&gt;

&lt;p&gt;Similar to our backend app, let's create the frontend app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx nx generate @nx/react:app packages/my-react-app &lt;span class="nt"&gt;--style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; if you encountered an error like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;An error occurred &lt;span class="k"&gt;while &lt;/span&gt;processing files &lt;span class="k"&gt;for &lt;/span&gt;the @nx/vite/plugin
libs/shared-ui/vite.config.ts: Cannot find module &lt;span class="s1"&gt;'ajv/dist/core'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simply, run this command &lt;code&gt;npm install ajv&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Importing Components Across Apps
&lt;/h3&gt;

&lt;p&gt;To use our new &lt;code&gt;Button&lt;/code&gt; component in &lt;code&gt;my-react-app&lt;/code&gt;, we simply import it using its alias defined in &lt;code&gt;package.json&lt;/code&gt; name property; &lt;code&gt;@my-awesome-nx-repo/shared-ui&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, find &lt;code&gt;packages/my-react-app/src/app/app.tsx&lt;/code&gt; (the main app file).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// packages/my-react-app/src/app/app.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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;react&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;Button&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;@my-awesome-nx-repo/shared-ui&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Import our shared button&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.module.css&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;function&lt;/span&gt; &lt;span class="nf"&gt;App&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;handleClick&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Button clicked from shared library!&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Welcome to my-react-app!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Click Me"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Use the shared button */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;This button comes from a shared library.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if you run &lt;code&gt;nx serve my-react-app&lt;/code&gt;, you'll see your React app with the shared button. Any change to &lt;code&gt;libs/shared-ui&lt;/code&gt; will instantly update in &lt;code&gt;my-react-app&lt;/code&gt; during development.&lt;/p&gt;

&lt;p&gt;This is because Nx knows the dependency and rebuilds only what's needed. It's a huge time-saver and makes developing complex UIs much more manageable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hot Reloading and Development Workflow
&lt;/h3&gt;

&lt;p&gt;Nx provides a smooth development experience with hot reloading. When you run &lt;code&gt;nx serve [project-name]&lt;/code&gt;, any changes you make to that project, or any library it depends on, will trigger a recompile and refresh your browser (for frontend apps) or restart your server (for backend apps). It is quite magical.&lt;/p&gt;

&lt;p&gt;This workflow is incredibly efficient. You modify a shared UI component in &lt;code&gt;libs/shared-ui&lt;/code&gt;, and all React apps that use it automatically update. You don't need to rebuild libraries manually or run separate watch commands. Nx handles it all. This rapid feedback loop is a big win for productivity.&lt;/p&gt;

&lt;p&gt;[newsletter_form form="2"]&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Nx Workspace Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fmayallo.com%2Fwp-content%2Fuploads%2F2025%2F06%2Flucas-santos-MiSPnHknw4w-unsplash-1024x683.avif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fmayallo.com%2Fwp-content%2Fuploads%2F2025%2F06%2Flucas-santos-MiSPnHknw4w-unsplash-1024x683.avif" alt="Nx Monorepo Guide: React &amp;amp; Node Fullstack App" width="1024" height="683"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@_staticvoid?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Lucas Santos&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/brown-and-black-round-decor-MiSPnHknw4w?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To truly master Nx, you need to grasp its architectural ideas. It's more than just a collection of files; it's a way of thinking about how the different parts of a software system relate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Apps (Packages) vs Libraries: When to Use Each
&lt;/h3&gt;

&lt;p&gt;This is a core concept in Nx. Knowing when to make something an &lt;code&gt;app&lt;/code&gt; and when it should be a &lt;code&gt;lib&lt;/code&gt; is important. It's not just about what it is, but what it does.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Applications (&lt;code&gt;packages/&lt;/code&gt; or apps/)&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Purpose&lt;/strong&gt;: These are the deployable units of your workspace. They are what users interact with, or what gets deployed to a server.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Examples&lt;/strong&gt;: A React web app, a Node.js API server, an Electron desktop app, a mobile app.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Characteristics&lt;/strong&gt;: They usually depend on libraries, but other applications generally don't depend on them. They often contain specific configurations for deployment.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Libraries (&lt;code&gt;libs/&lt;/code&gt;)&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Purpose&lt;/strong&gt;: These are reusable, shareable units of code within your workspace. They are meant to be consumed by applications or other libraries.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Examples&lt;/strong&gt;: UI component library, data access layer, utility functions, shared types, authentication logic.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Characteristics&lt;/strong&gt;: They should be cohesive and focused on a &lt;a href="https://mayallo.com/solid-single-responsibility-principle/" rel="noopener noreferrer"&gt;single responsibility&lt;/a&gt;. They often depend on other libraries but should generally &lt;em&gt;not&lt;/em&gt; depend on applications. This promotes modularity and reusability.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Choosing correctly ensures a cleaner architecture. If you find yourself copying code between applications, you probably need a new library. If a project contains UI components &lt;em&gt;and&lt;/em&gt; API logic, it should probably be split into a UI library and an API application. This enforces better separation of concerns.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency Graph Visualization
&lt;/h3&gt;

&lt;p&gt;One of Nx's most powerful features is its ability to build and visualize the dependency graph of your workspace. It maps out how every project (app or lib) connects to others. This graph is not just for show; Nx uses it to figure out what needs to be built or tested when you make a change.&lt;/p&gt;

&lt;p&gt;To see your graph, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx nx graph
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command opens a browser window showing a visual representation of your projects and their dependencies. You can click on projects to see their specific connections.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmayallo.com%2Fwp-content%2Fuploads%2F2025%2F06%2Fchrome_7Wta3DFlsu-1.avif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmayallo.com%2Fwp-content%2Fuploads%2F2025%2F06%2Fchrome_7Wta3DFlsu-1.avif" alt="Nx Monorepo Guide: React &amp;amp; Node Fullstack App" width="714" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Module Boundaries and Import Restrictions
&lt;/h3&gt;

&lt;p&gt;Nx lets you enforce rules about how projects can import each other. This is called "&lt;a href="https://nx.dev/features/enforce-module-boundaries" rel="noopener noreferrer"&gt;Module Boundaries&lt;/a&gt;." It helps maintain a healthy, layered architecture and prevents spaghetti code. For example, you might want to stop a frontend UI library from importing a backend database library. This is a common problem in big systems, and Nx helps prevent it.&lt;/p&gt;

&lt;p&gt;You define these rules in your root &lt;code&gt;.eslint.config.mjs&lt;/code&gt; file using &lt;code&gt;enforceBuildableLibDependency&lt;/code&gt; and &lt;code&gt;depConstraints&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// .eslint.config.mjs example showing depConstraints&lt;/span&gt;

&lt;span class="c1"&gt;// other configs&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;files&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;**/*.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;**/*.tsx&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;**/*.js&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;**/*.jsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;rules&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;@nx/enforce-module-boundaries&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&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;enforceBuildableLibDependency&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;allow&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;^.*/eslint(&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;.base)?&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;.config&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;.[cm]?js$&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;depConstraints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="c1"&gt;// Here are our rules!&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;sourceTag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scope:frontend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Projects with this tag&lt;/span&gt;
            &lt;span class="na"&gt;onlyDependOnLibsWithTags&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;scope:shared&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;scope:frontend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// Can only depend on these tags&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;sourceTag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scope:backend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;onlyDependOnLibsWithTags&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;scope:shared&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;scope:backend&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;span class="na"&gt;sourceTag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scope:shared&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;onlyDependOnLibsWithTags&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;scope:shared&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// Shared libs can only depend on other shared libs&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="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="c1"&gt;// other configs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make these rules work, you add "tags" to your projects in their &lt;code&gt;package.json&lt;/code&gt; files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;packages/my-react-app/project.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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@my-awesome-nx-repo/my-react-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;other&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;details&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nx"&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;"tags"&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:frontend"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Apply&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;here&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;libs/shared-ui/project.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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@my-awesome-nx-repo/shared-ui"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;other&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;details&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nx"&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;"tags"&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:shared"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Apply&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;here&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;Try to violate these rules by removing the &lt;code&gt;scope:shared&lt;/code&gt; dependent from the React app, then run &lt;code&gt;npx nx lint&lt;/code&gt; &lt;code&gt;my-react-app&lt;/code&gt;, you will get the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;error  A project tagged with &lt;span class="s2"&gt;"scope:frontend"&lt;/span&gt; can only depend on libs tagged with &lt;span class="s2"&gt;"scope:frontend"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps enforce a clean architecture, like preventing an app from depending on a library that is not allowed to be called.&lt;/p&gt;

&lt;h3&gt;
  
  
  Managing Dependencies in Nx Workspace
&lt;/h3&gt;

&lt;p&gt;In a monorepo, managing dependencies can be done using two strategies:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Centralized Dependency Management&lt;/strong&gt;: All dependencies are defined in the root &lt;code&gt;package.json&lt;/code&gt;, shared across all apps and libraries.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Pros:&lt;/em&gt; Simplifies management, ensures consistency, and reduces duplication.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Cons:&lt;/em&gt; Less flexibility for individual projects to use different versions of dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Explicit Project-Specific Dependencies:&lt;/strong&gt; Dependencies are scoped to individual apps or libraries, allowing each project to manage its own.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Pros:&lt;/em&gt; Provides flexibility and isolation for each project.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Cons:&lt;/em&gt; Increases complexity, may lead to duplication, and code sharing becomes more challenging.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, it is a tradeoff as usual, but I would stick to the centralized dependency strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Nx Monorepo isn't a one-size-fits-all solution, but when it fits, it transforms how teams build and scale applications.&lt;/p&gt;

&lt;p&gt;It's ideal for large, interconnected projects that benefit from shared code, consistent tooling, and fast CI/CD. While it might be overkill for small or isolated projects.&lt;/p&gt;

&lt;p&gt;For most modern development workflows, Nx offers the structure, performance, and flexibility to build with confidence and maintain long-term efficiency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Think about it
&lt;/h2&gt;

&lt;p&gt;If you enjoyed this article, I’d truly appreciate it if you could share it—it really motivates me to keep creating more helpful content!&lt;/p&gt;

&lt;p&gt;If you’re interested in exploring more, check out these articles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/typescript-type-vs-interface/" rel="noopener noreferrer"&gt;TypeScript Type vs Interface? The Answer Is Type!&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/solid-single-responsibility-principle/" rel="noopener noreferrer"&gt;Do you really know, what is Single Responsibility Principle?&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/unit-integration-e2e-testing-using-jest/" rel="noopener noreferrer"&gt;Unit, Integration, and E2E Testing in One Example Using Jest&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/bdd-fundamentals-jest-cucumber-nodejs/" rel="noopener noreferrer"&gt;BDD Fundamentals with Jest and Cucumber&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for sticking with me until the end—I hope you found this article valuable and enjoyable!&lt;/p&gt;

</description>
      <category>nx</category>
      <category>monorepo</category>
      <category>programming</category>
      <category>typescript</category>
    </item>
    <item>
      <title>TypeScript Type Vs Interface? The Answer Is Type!</title>
      <dc:creator>Mohamed Mayallo</dc:creator>
      <pubDate>Tue, 20 May 2025 07:00:00 +0000</pubDate>
      <link>https://dev.to/mayallo/typescript-type-vs-interface-the-answer-is-type-38g5</link>
      <guid>https://dev.to/mayallo/typescript-type-vs-interface-the-answer-is-type-38g5</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In TypeScript, you can define custom shapes using &lt;code&gt;type&lt;/code&gt; aliases or &lt;code&gt;interface&lt;/code&gt;. But when it comes to choosing between them, many developers ask: &lt;strong&gt;"TypeScript Type vs Interface?"&lt;/strong&gt; The answer is increasingly clear: &lt;strong&gt;use &lt;code&gt;type&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;While both share similarities, &lt;code&gt;type&lt;/code&gt; offers more flexibility, supports complex patterns, and aligns better with modern TypeScript and frameworks. In this guide, you'll learn the differences, strengths, and why &lt;code&gt;type&lt;/code&gt; is the better default.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Types and Interfaces?
&lt;/h2&gt;

&lt;p&gt;Both &lt;code&gt;type&lt;/code&gt; and &lt;code&gt;interface&lt;/code&gt; define object shapes or function signatures:&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;// Using type&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Point&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SetPoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Using interface&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Point&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;SetPoint&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They look and behave similarly here, but the differences appear in advanced use cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Type Wins in Modern TypeScript
&lt;/h2&gt;

&lt;p&gt;But why are types preferable?&lt;/p&gt;

&lt;h3&gt;
  
  
  1- More Expressive
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;type&lt;/code&gt; is more versatile and can describe things that &lt;code&gt;interface&lt;/code&gt; can't, like unions, primitives, tuples, mapped types, and conditional types.&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;// Using `type` to alias primitive types.&lt;/span&gt;
&lt;span class="c1"&gt;// `interface` cannot be used with primitives like `string`, `number`, etc.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="c1"&gt;// Using `type` to define a union type.&lt;/span&gt;
&lt;span class="c1"&gt;// `interface` does not support union types directly.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&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="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;error&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="c1"&gt;// Using `type` to define a tuple.&lt;/span&gt;
&lt;span class="c1"&gt;// Tuples can't be defined using `interface`; `type` is required.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Coordinates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 

&lt;span class="c1"&gt;// Using `type` with mapped types to create a read-only version of a given type.&lt;/span&gt;
&lt;span class="c1"&gt;// This utilizes TypeScript's advanced type system, which `type` handles more flexibly than `interface`.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nb"&gt;Readonly&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&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="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="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Conditional type (cannot be achieved using `interface`)&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ResponseData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&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="nl"&gt;data&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;error&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="c1"&gt;// When the flag is true, the shape has 'data'&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SuccessResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ResponseData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kc"&gt;true&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;// { success: true; data: string }&lt;/span&gt;

&lt;span class="c1"&gt;// When the flag is false, the shape has 'error'&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ErrorResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ResponseData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kc"&gt;false&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;// { success: false; error: string }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interfaces can’t express these patterns.&lt;/p&gt;

&lt;h3&gt;
  
  
  2- Safer and More Predictable
&lt;/h3&gt;

&lt;p&gt;Only &lt;code&gt;interface&lt;/code&gt; supports declaration merging:&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;verbose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Becomes: { debug: boolean; verbose: boolean }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can be helpful in rare cases but risky in most—it leads to hard-to-debug surprises. &lt;code&gt;type&lt;/code&gt; prevents accidental redefinitions.&lt;/p&gt;

&lt;h3&gt;
  
  
  3- Works Everywhere
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;type&lt;/code&gt; can extend both types and interfaces, and you can use intersection (&lt;code&gt;&amp;amp;&lt;/code&gt;) for composition.&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;B&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Combined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes &lt;code&gt;type&lt;/code&gt; more consistent for real-world scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  4- Ideal for Functional and React Patterns
&lt;/h3&gt;

&lt;p&gt;Modern frontend libraries and tools like &lt;strong&gt;React&lt;/strong&gt;, &lt;strong&gt;Redux&lt;/strong&gt;, and &lt;strong&gt;Zod&lt;/strong&gt; tend to favor &lt;code&gt;type&lt;/code&gt; aliases due to their flexibility, especially when working with &lt;strong&gt;&lt;a href="https://mayallo.com/typescript-discriminated-unions/" rel="noopener noreferrer"&gt;discriminated unions&lt;/a&gt;&lt;/strong&gt;, complex props, or functional patterns.&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;// Simple React props using a type alias&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Discriminated union for Redux-like actions&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;'&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stop&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// This is a discriminated union: a union of object types&lt;/span&gt;
&lt;span class="c1"&gt;// that share a common `type` field used to determine the variant.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can’t define union types or complex props this cleanly with &lt;code&gt;interface&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Interface Makes Sense
&lt;/h2&gt;

&lt;p&gt;While &lt;code&gt;type&lt;/code&gt; is generally more flexible, &lt;code&gt;interface&lt;/code&gt; still plays a valuable role in certain scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Public APIs / Libraries&lt;/strong&gt; – &lt;code&gt;interface&lt;/code&gt; supports &lt;strong&gt;declaration merging&lt;/strong&gt;, which allows libraries to be extended or augmented safely.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;OOP patterns&lt;/strong&gt; where classes implement contracts
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IUser&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&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="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Admin&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;IUser&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;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;login&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;But even here, you can use &lt;code&gt;type&lt;/code&gt; instead.&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;IUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&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="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Admin&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;IUser&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;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;login&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;While both versions work, &lt;code&gt;interface&lt;/code&gt; tends to be preferred in OOP-heavy codebases for its semantic clarity and support for extension via &lt;code&gt;extends&lt;/code&gt; or declaration merging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In most real-world TypeScript codebases, &lt;code&gt;type&lt;/code&gt; outshines &lt;code&gt;interface&lt;/code&gt;. It handles everything from unions to tuples, supports mapped and conditional types, and avoids unexpected behaviors like declaration merging.&lt;/p&gt;

&lt;p&gt;At the end of the day, unless you’re exposing a public OOP-style API or need declaration merging, stick with &lt;code&gt;type&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Think Of It
&lt;/h2&gt;

&lt;p&gt;If you enjoyed this article, I’d truly appreciate it if you could share it—it really motivates me to keep creating more helpful content!&lt;/p&gt;

&lt;p&gt;If you’re interested in exploring more, check out these articles.&lt;a href="https://mayallo.com/wp-admin/post.php?post=867&amp;amp;action=edit" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/asynchronous-javascript/" rel="noopener noreferrer"&gt;&lt;strong&gt;4 Ways To Handle Asynchronous JavaScript&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;a href="https://mayallo.com/overloading-vs-overriding-typescript/" rel="noopener noreferrer"&gt;Overloading vs Overriding in TypeScript&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;a href="https://mayallo.com/typescript-as-const/" rel="noopener noreferrer"&gt;How to Use as const in TypeScript Effectively&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And to learn more, please check the &lt;a href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces" rel="noopener noreferrer"&gt;TypeScript Documentation&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;Thanks for sticking with me until the end—I hope you found this article valuable and enjoyable!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>programming</category>
      <category>webdev</category>
      <category>coding</category>
    </item>
    <item>
      <title>Deep Copy vs Shallow Copy in JavaScript: Complete Guide</title>
      <dc:creator>Mohamed Mayallo</dc:creator>
      <pubDate>Sun, 18 May 2025 08:27:00 +0000</pubDate>
      <link>https://dev.to/mayallo/deep-copy-vs-shallow-copy-in-javascript-complete-guide-3ph1</link>
      <guid>https://dev.to/mayallo/deep-copy-vs-shallow-copy-in-javascript-complete-guide-3ph1</guid>
      <description>&lt;h2&gt;
  
  
  Understanding Object References in JavaScript
&lt;/h2&gt;

&lt;p&gt;Have you ever changed something you thought was a separate copy, only to find you messed up the original data too? Yeah, that happens a lot if you don't get how JavaScript handles different kinds of copying; deep copy vs shallow copy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Value vs Reference Types
&lt;/h3&gt;

&lt;p&gt;JavaScript has these two main ways it thinks about data: by value and by reference. Simple stuff like numbers, strings, booleans, null, and undefined are value types. When you copy them, JavaScript just makes a whole new one. A separate thing entirely. Changing the new one never affects the old one.&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;let&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&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;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// b gets a copy of the value 10&lt;/span&gt;
&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&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;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: 10 (a is unchanged)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, objects, arrays, and functions are reference types. When you assign one variable to another, you're not copying the actual data. Instead, you're copying the &lt;em&gt;reference&lt;/em&gt; to where that data lives in the computer's memory.&lt;/p&gt;

&lt;p&gt;It's like having two street signs pointing to the same house. You change the house through one sign, the change is there if you use the other sign, too. It can be confusing, is it not?&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;let&lt;/span&gt; &lt;span class="nx"&gt;obj1&lt;/span&gt; &lt;span class="o"&gt;=&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;Alice&lt;/span&gt;&lt;span class="dl"&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;obj2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// obj2 gets a copy of the reference to the object&lt;/span&gt;
&lt;span class="nx"&gt;obj2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;obj1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: Bob (obj1 was changed!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Problem with Direct Object Assignment
&lt;/h3&gt;

&lt;p&gt;Assigning one object variable to another using the simple equals sign (&lt;code&gt;=&lt;/code&gt;) creates this reference copy. This is where things get messy if you aren't expecting it. You think you've made a copy to work with, but you've just made another handle for the exact same object in memory. Modifying the 'copy' variable directly modifies the original object.&lt;/p&gt;

&lt;p&gt;Let's say you get some data from an API and store it in a variable, maybe called &lt;code&gt;userData&lt;/code&gt;. Then you need to modify this data before displaying it, but you also want to keep the original &lt;code&gt;userData&lt;/code&gt; untouched for later use. If you just do &lt;code&gt;let displayData = userData;&lt;/code&gt; and then change &lt;code&gt;displayData&lt;/code&gt;, you've just changed your original &lt;code&gt;userData&lt;/code&gt;.&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;let&lt;/span&gt; &lt;span class="nx"&gt;originalUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&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="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;Charlie&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;modifiedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;originalUser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Just copying the reference&lt;/span&gt;

&lt;span class="nx"&gt;modifiedUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;David&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Changes originalUser.name too!&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;originalUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: David&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore, if your goal is to have a separate version of the object that you can change without affecting the source, a direct assignment simply doesn't do the job you think it might.&lt;/p&gt;

&lt;h3&gt;
  
  
  Copy Operations and Memory Management
&lt;/h3&gt;

&lt;p&gt;JavaScript supports two kinds of copying: &lt;strong&gt;shallow&lt;/strong&gt; and &lt;strong&gt;deep&lt;/strong&gt;. Both involve different levels of memory handling.&lt;/p&gt;

&lt;p&gt;Grasping how memory works in each case helps explain why deep copying tends to be slower and more resource-intensive. So, let’s break down both types in more detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shallow Copy: Methods and Limitations
&lt;/h2&gt;

&lt;p&gt;When you make a shallow copy, a new memory is allocated for the &lt;strong&gt;top-level&lt;/strong&gt; object or array structure. However, the nested objects inside still refer to the same memory locations as the original.&lt;/p&gt;

&lt;p&gt;It's like a new outer box, but the things inside are the originals. It's faster than a deep copy because it does less work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Built-in Shallow Copy Techniques
&lt;/h3&gt;

&lt;p&gt;JavaScript offers several easy ways to create shallow copies.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;Object.assign()&lt;/code&gt;&lt;/strong&gt;: This method copies &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Enumerability_and_ownership_of_properties" rel="noopener noreferrer"&gt;enumerable own properties&lt;/a&gt; from one or more source objects to a target object. The target object is then returned. It's been around for a while, very reliable for flat objects.
&lt;/li&gt;
&lt;/ul&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;original&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&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="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&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;shallowCopy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;shallowCopy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Changes only shallowCopy.a&lt;/span&gt;
&lt;span class="nx"&gt;shallowCopy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Changes original.b.c and shallowCopy.b.c&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;original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: 1&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;original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&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="c1"&gt;// Output: 200 (Still shared!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Spread syntax (&lt;code&gt;...&lt;/code&gt;)&lt;/strong&gt;: This is perhaps the most modern and often cleanest way for arrays and objects. It 'spreads' the properties or elements from the source into a new object or array literal. It does essentially the same thing as &lt;code&gt;Object.assign()&lt;/code&gt; for objects and provides a nice syntax for arrays.
&lt;/li&gt;
&lt;/ul&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;originalArr&lt;/span&gt; &lt;span class="o"&gt;=&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;d&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&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;shallowCopyArr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;originalArr&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// Shallow copy of array&lt;/span&gt;

&lt;span class="nx"&gt;shallowCopyArr&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="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Changes only shallowCopyArr[0]&lt;/span&gt;
&lt;span class="nx"&gt;shallowCopyArr&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="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Changes originalArr[1].d and shallowCopyArr[1].d&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;originalArr&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;// Output: 1&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;originalArr&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="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: 400 (Still shared!)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&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="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&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;shallowCopyObj&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="nx"&gt;originalObj&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// Shallow copy of object&lt;/span&gt;

&lt;span class="nx"&gt;shallowCopyObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Changes only shallowCopyObj.a&lt;/span&gt;
&lt;span class="nx"&gt;shallowCopyObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Changes originalObj.b.c and shallowCopyObj.b.c&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;originalObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: 1&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;originalObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&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="c1"&gt;// Output: 200 (Still shared!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Array methods (&lt;code&gt;slice()&lt;/code&gt;, &lt;code&gt;concat()&lt;/code&gt;)&lt;/strong&gt;: For arrays specifically, methods like &lt;code&gt;slice()&lt;/code&gt; without arguments or &lt;code&gt;concat()&lt;/code&gt; with an empty array also create shallow copies. These are classic methods, reliable for many years now.
&lt;/li&gt;
&lt;/ul&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;originalArrOld&lt;/span&gt; &lt;span class="o"&gt;=&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&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;shallowCopyArrOld1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;originalArrOld&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&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;shallowCopyArrOld2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[].&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalArrOld&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;shallowCopyArrOld1&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="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Changes originalArrOld[1].e and shallowCopyArrOld1[1].e&lt;/span&gt;
&lt;span class="nx"&gt;shallowCopyArrOld2&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="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Changes originalArrOld[1].e, shallowCopyArrOld1[1].e, and shallowCopyArrOld2[1].e&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;originalArrOld&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="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: 600 (All shared!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Nested Object Behavior
&lt;/h3&gt;

&lt;p&gt;As you saw, the crucial thing about shallow copies is their behavior with nested objects. The copy process only goes &lt;strong&gt;one level deep&lt;/strong&gt;. For that reason, the nested object &lt;code&gt;{ c: 2 }&lt;/code&gt;, &lt;code&gt;{ d: 4 }&lt;/code&gt;, or &lt;code&gt;{ e: 5 }&lt;/code&gt; is still the &lt;em&gt;exact same object&lt;/em&gt; in memory? Changing it through &lt;em&gt;any&lt;/em&gt; of the variables (&lt;code&gt;original&lt;/code&gt;, &lt;code&gt;shallowCopy&lt;/code&gt;, &lt;code&gt;shallowCopyObj&lt;/code&gt;, etc.) affects all of them.&lt;/p&gt;

&lt;p&gt;This sharing of nested references is the primary reason shallow copy isn't suitable when you need complete independence between the original and the copy, especially when dealing with complex data structures or state management, where immutability is important. It's a common source of bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deep Copy: Complete Object Duplication
&lt;/h2&gt;

&lt;p&gt;Sometimes you need a true clone, a completely independent replica where changing the copy &lt;em&gt;never&lt;/em&gt; impacts the original, no matter how deep the nesting goes. This is where deep copies come in.&lt;/p&gt;

&lt;p&gt;A deep copy, on the other hand, allocates entirely new memory for &lt;strong&gt;every&lt;/strong&gt; part of the object structure, including all nested objects and arrays. This requires more processing time and more memory space compared to a shallow copy.&lt;/p&gt;

&lt;p&gt;It's like unpacking a box and then making a brand new copy of &lt;em&gt;everything&lt;/em&gt; inside and putting it into a new box. This way, nothing in the new box points back to the old box's contents.&lt;/p&gt;

&lt;h3&gt;
  
  
  JSON Method: Syntax and Limitations
&lt;/h3&gt;

&lt;p&gt;The most common trick developers used for a long time to achieve a deep copy was &lt;code&gt;JSON.parse(JSON.stringify(obj))&lt;/code&gt;. How does this work? &lt;code&gt;JSON.stringify()&lt;/code&gt; converts a JavaScript object into a JSON string. This string representation contains only the data, not the references. Then, &lt;code&gt;JSON.parse()&lt;/code&gt; converts that string back into a new JavaScript object. Since it's built from a string, all the objects and arrays within it are newly created.&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;originalDeep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&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="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&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;deepCopyJSON&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalDeep&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;deepCopyJSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Changes only deepCopyJSON.a&lt;/span&gt;
&lt;span class="nx"&gt;deepCopyJSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Changes only deepCopyJSON.b.c&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;originalDeep&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: 1&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;originalDeep&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&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="c1"&gt;// Output: 2 (Original is untouched!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method is simple and works well for basic data objects that contain only primitive types, arrays, and other plain objects. However, it has significant limitations you must be aware of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Loses Data Types:&lt;/strong&gt; It cannot handle certain JavaScript data types. Functions, &lt;code&gt;undefined&lt;/code&gt;, &lt;code&gt;NaN&lt;/code&gt;, &lt;code&gt;Infinity&lt;/code&gt;, and &lt;code&gt;RegExp&lt;/code&gt; objects turn into &lt;code&gt;null&lt;/code&gt; or are simply dropped during stringification. Dates become strings. Maps and Sets become empty objects. This is because the JSON format itself doesn't have standard representations for these JavaScript-specific concepts.
&lt;/li&gt;
&lt;/ul&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;objA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&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;objB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;objA&lt;/span&gt;&lt;span class="p"&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;objA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// true&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;objB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// false (Loses the Date type!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Circular_reference" rel="noopener noreferrer"&gt;Circular References&lt;/a&gt;:&lt;/strong&gt; Objects with circular references (where a property of an object refers back to the object itself or one of its ancestors) will cause &lt;code&gt;JSON.stringify()&lt;/code&gt; to throw an error.
&lt;/li&gt;
&lt;/ul&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;objA&lt;/span&gt; &lt;span class="o"&gt;=&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;A&lt;/span&gt;&lt;span class="dl"&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;objB&lt;/span&gt; &lt;span class="o"&gt;=&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;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;objA&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;objA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;objB&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// JSON.parse(JSON.stringify(objA)); // Throws TypeError&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, while easy, this method is far from a universal deep copy solution. You might run into trouble unexpectedly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structured Clone API
&lt;/h3&gt;

&lt;p&gt;Modern JavaScript introduces the &lt;code&gt;[structuredClone()](https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone)&lt;/code&gt; function, which handles many of the limitations above. It's becoming the standard way to do this.&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;original&lt;/span&gt; &lt;span class="o"&gt;=&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;Alpha&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&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;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]]),&lt;/span&gt;
  &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;original&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;copy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;structuredClone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&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;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&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;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// true&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;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// true&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;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;        &lt;span class="c1"&gt;// true (circular reference preserved)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;Date&lt;/code&gt;, &lt;code&gt;RegExp&lt;/code&gt;, &lt;code&gt;Map&lt;/code&gt;, &lt;code&gt;Set&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;ArrayBuffer&lt;/code&gt;, &lt;code&gt;Blob&lt;/code&gt;, &lt;code&gt;File&lt;/code&gt;, &lt;code&gt;FileList&lt;/code&gt;, &lt;code&gt;ImageData&lt;/code&gt;, &lt;code&gt;MessagePort&lt;/code&gt;, &lt;code&gt;ImageBitmap&lt;/code&gt;, &lt;code&gt;Error&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;NaN&lt;/code&gt;, &lt;code&gt;Infinity&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Circular references.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it still has drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Functions are not allowed&lt;/strong&gt;: they’ll be dropped or throw an error.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;structuredClone&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;fn&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="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// Throws DataCloneError&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Doesn't preserve the prototype chain&lt;/strong&gt;: class instances lose their methods.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&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;Hello &lt;/span&gt;&lt;span class="dl"&gt;'&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;value&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;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&lt;/span&gt;&lt;span class="dl"&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;clone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;structuredClone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&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;clone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;           &lt;span class="c1"&gt;// "World"&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;clone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;           &lt;span class="c1"&gt;// undefined&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;clone&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Doesn’t support getters/setters or property descriptors&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SecretBox&lt;/span&gt; &lt;span class="p"&gt;{&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secret&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="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;hiddenValue&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;_value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nf"&gt;hiddenValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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;Trying to set to:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;val&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;original&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SecretBox&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;clone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;structuredClone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Original still works&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;original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hiddenValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Output: 'secret'&lt;/span&gt;
&lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hiddenValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// Logs: Trying to set to: new&lt;/span&gt;

&lt;span class="c1"&gt;// Clone fails&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;clone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hiddenValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;     &lt;span class="c1"&gt;// Output: undefined (getter is lost)&lt;/span&gt;
&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hiddenValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;         &lt;span class="c1"&gt;// No log (setter is gone)&lt;/span&gt;

&lt;span class="c1"&gt;// Prototype check&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;clone&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;SecretBox&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false&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="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPrototypeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;SecretBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s a much better option than JSON for most modern needs, but not perfect for all use cases, especially when behavior or prototypes matter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Library Solutions: Lodash
&lt;/h3&gt;

&lt;p&gt;If you need a more flexible, production-grade deep clone and don't want to write your own, libraries like &lt;strong&gt;&lt;a href="https://lodash.com/docs/#cloneDeep" rel="noopener noreferrer"&gt;Lodash&lt;/a&gt;&lt;/strong&gt; are a great choice. These libraries have already solved many of the edge cases that custom implementations miss.&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;// npm install lodash&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;obj&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&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;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&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;Hello &lt;/span&gt;&lt;span class="dl"&gt;'&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;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;val&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;value&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;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;obj&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;clone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cloneDeep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;clone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                        &lt;span class="c1"&gt;// "World"&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;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;              &lt;span class="c1"&gt;// "Hello"&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;clone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                 &lt;span class="c1"&gt;// "Hi"&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;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// true&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;clone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;     &lt;span class="c1"&gt;// true&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;clone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                     &lt;span class="c1"&gt;// Handles the circular refs (No errors)&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;clone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                        &lt;span class="c1"&gt;// ƒ greet() (Doesn't lose functions)&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;clone&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;           &lt;span class="c1"&gt;// true&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;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                       &lt;span class="c1"&gt;// "World"&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;clone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                          &lt;span class="c1"&gt;// "World" (Doesn't lose getters and setters)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you see, it mostly solves all the problems.&lt;/p&gt;

&lt;p&gt;Libraries are generally the recommended path for complex deep cloning needs because they handle many tricky situations for you. Why reinvent the wheel when someone else built a perfectly good one, right?&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Recursive Implementation
&lt;/h3&gt;

&lt;p&gt;If you need total control, maybe you want to copy specific things and ignore others; you might need to write your own deep copy function.&lt;/p&gt;

&lt;p&gt;However, keep in mind, writing a robust custom deep clone function is quite complicated. It needs to account for all built-in types, handle inheritance (prototypes), property attributes, and those circular references.&lt;/p&gt;

&lt;p&gt;Because of the complexity, this is usually only worth doing when libraries don't meet your requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use Shallow vs Deep Copy
&lt;/h2&gt;

&lt;p&gt;How do you choose between shallow and deep copy?&lt;/p&gt;

&lt;p&gt;It comes down to the structure of your data and what you intend to do with the copy. No single rule applies to every situation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use shallow copy when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Your object or array is flat (no nested objects/arrays).&lt;/li&gt;
&lt;li&gt;  You only need to modify properties directly on the top level.&lt;/li&gt;
&lt;li&gt;  Performance is critical, and shared nested references are acceptable or won't be modified.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use deep copy when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Your object or array has nested objects or arrays.&lt;/li&gt;
&lt;li&gt;  You need complete independence between the original and the copy, allowing modification of nested structures without affecting the source.&lt;/li&gt;
&lt;li&gt;  Immutability of the entire structure is required.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;JavaScript offers several approaches to copying objects, each with distinct trade-offs. Shallow copies (like &lt;code&gt;Object.assign()&lt;/code&gt; or spread operators) are fast and memory-efficient but only duplicate the top level, leaving nested structures vulnerable to unintended side effects.&lt;/p&gt;

&lt;p&gt;On the other side, deep copies provide complete independence by duplicating everything, though at the cost of performance and memory. And we covered some approaches to handle it.&lt;/p&gt;

&lt;p&gt;The right choice depends on your specific situation, the complexity of your data, performance needs, and which limitations you can accept.&lt;/p&gt;

&lt;p&gt;By understanding these trade-offs, you can make informed decisions that lead to more predictable, bug-free code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Think about it
&lt;/h2&gt;

&lt;p&gt;If you enjoyed this article, I’d truly appreciate it if you could share it; it really motivates me to keep creating more helpful content!&lt;/p&gt;

&lt;p&gt;If you’re interested in exploring more, check out these articles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/facade-vs-proxy-vs-adapter-design-patterns/" rel="noopener noreferrer"&gt;Facade vs Proxy vs Adapter Design Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/solid-single-responsibility-principle/" rel="noopener noreferrer"&gt;SOLID: Single Responsibility Principle&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/unit-integration-e2e-testing-using-jest/" rel="noopener noreferrer"&gt;Unit, Integration, and E2E Testing using Jest&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/javascript-get-yesterday-date/" rel="noopener noreferrer"&gt;How to get Yesterday's date in Javascript&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for sticking with me until the end. I hope you found this article valuable and enjoyable!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>typescript</category>
    </item>
    <item>
      <title>MongoDB Views or Materialized Views: When to Use?</title>
      <dc:creator>Mohamed Mayallo</dc:creator>
      <pubDate>Tue, 13 May 2025 05:59:05 +0000</pubDate>
      <link>https://dev.to/mayallo/mongodb-views-or-materialized-views-when-to-use-46d8</link>
      <guid>https://dev.to/mayallo/mongodb-views-or-materialized-views-when-to-use-46d8</guid>
      <description>&lt;h2&gt;
  
  
  Intoduction
&lt;/h2&gt;

&lt;p&gt;MongoDB offers powerful tools to simplify data access and improve performance. Among these tools are &lt;strong&gt;Standard Views&lt;/strong&gt; and &lt;strong&gt;Materialized Views&lt;/strong&gt;, two approaches that allow you to shape how data is read and presented, each with its own trade-offs and use cases.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore the differences between the two and when to use each effectively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I created a small Node.js server to compare between them and guide you how to create and refresh both programmatically, Find it &lt;a href="https://github.com/Mohamed-Mayallo/mongodb-views-vs-materialized-views" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a MongoDB Standard View?
&lt;/h2&gt;

&lt;p&gt;So, you're working with MongoDB and hear about these "view" things. Are they the same? Not quite.&lt;/p&gt;

&lt;p&gt;A MongoDB Standard View (or MongoDB View) is essentially a saved query (aggregation pipeline). It acts like a &lt;strong&gt;virtual collection&lt;/strong&gt;. When you query the view, MongoDB runs the saved query against the real collections &lt;em&gt;at that moment&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  It's &lt;strong&gt;logical&lt;/strong&gt;: Doesn't store any data itself, just the definition.&lt;/li&gt;
&lt;li&gt;  It's &lt;strong&gt;read-only&lt;/strong&gt;: You can't write data to a view.&lt;/li&gt;
&lt;li&gt;  It uses &lt;strong&gt;aggregation pipelines&lt;/strong&gt;: This is how you define what the view shows.&lt;/li&gt;
&lt;li&gt;  It's &lt;strong&gt;metadata&lt;/strong&gt;: The view definition is stored, not the results. So, zero extra storage footprint for the data itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, it's a shortcut; instead of writing a very long, complex aggregation pipeline over and over, you save this definition as a virtual collection for later use.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Materialized View?
&lt;/h2&gt;

&lt;p&gt;Unlike standard views, a materialized view &lt;em&gt;actually stores data&lt;/em&gt;. It's basically a &lt;strong&gt;regular collection&lt;/strong&gt; that holds the pre-computed results of an aggregation query.&lt;/p&gt;

&lt;p&gt;Guess what? MongoDB doesn't &lt;em&gt;natively&lt;/em&gt; support them like some SQL databases do (not yet, anyway). When we talk about materialized views in MongoDB, we mean a &lt;em&gt;pattern&lt;/em&gt; you implement yourself, another collection (the materialized view) that holds pre-computed results.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Stores results physically&lt;/strong&gt;: You run an aggregation query and save its output into a &lt;em&gt;real&lt;/em&gt;, separate collection.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Precomputed&lt;/strong&gt;: The results are already calculated and stored.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Simulates denormalization&lt;/strong&gt;: Kinda like creating a purpose-built table holding exactly the data you need for fast reads.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, you're trading real-time data freshness for speed, because reading from this pre-built collection is way faster than running a complex aggregation every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  MongoDB Views Vs Materialized Views
&lt;/h2&gt;

&lt;p&gt;Well, let's compare them based on some criteria.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data Freshness&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Views&lt;/strong&gt;: Always show the latest data because they run the query live. What you see is what's in the base collection &lt;em&gt;right now&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Materialized Views&lt;/strong&gt;: Only as fresh as the last refresh. If you refresh it once a day, the data could be up to 24 hours old.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Performance Implications&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Views&lt;/strong&gt;: Read performance depends entirely on the underlying query and collections. Complex aggregations on large datasets? Will be slow. Simple filter? Probably fast.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Materialized Views&lt;/strong&gt;: Reads are typically super fast because it's just querying a regular collection with precomputed data. Writes, though? You add overhead because you need to run the aggregation and write the results periodically (the refresh).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Storage Considerations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Views&lt;/strong&gt;: Tiny footprint (neglicable). Just stores the query definition.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Materialized Views&lt;/strong&gt;: Can use significant storage, because you're duplicating data (the results of the query). The size depends on the output of your aggregation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Maintenance Overhead&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Views&lt;/strong&gt;: Almost none. Define it once, use it. Maybe update the definition if your needs change.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Materialized Views&lt;/strong&gt;: You have to build and manage the refresh process. How often? How to handle failures? What if the source data changes structure? It's definitely more work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Native Support in MongoDB&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Views&lt;/strong&gt;: Fully supported feature.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Materialized Views&lt;/strong&gt;: Not supported at this time. It's a pattern. You use standard MongoDB features like aggregation (&lt;code&gt;$out&lt;/code&gt; or &lt;code&gt;$merge&lt;/code&gt;) and maybe schedulers or Change Streams to build it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Security &amp;amp; Abstraction Capabilities&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Views&lt;/strong&gt;: Great for this. You can grant read access &lt;em&gt;only&lt;/em&gt; to the view, effectively hiding fields or documents from users who shouldn't see them.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Materialized Views&lt;/strong&gt;: It's just another collection. You need to manage its security access separately, just like any other collection.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When To Use Views vs Materialized Views?
&lt;/h2&gt;

&lt;p&gt;Why bother with regular views then?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Query Abstraction&lt;/strong&gt;: Hide complex aggregation logic behind a simple view name. Makes life easier for application devs who just want to query &lt;code&gt;order_analytics_view&lt;/code&gt; instead of writing a &lt;a href="https://github.com/Mohamed-Mayallo/mongodb-views-vs-materialized-views/blob/main/scripts/3-create-standard-view.js" rel="noopener noreferrer"&gt;complex pipeline&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Data Security&lt;/strong&gt;: You can create views that only show certain fields or documents to specific users or roles. Kinda like a security layer without needing complex application logic. Like, maybe show &lt;code&gt;user_basic_info_view&lt;/code&gt; to regular staff, but the full &lt;code&gt;users&lt;/code&gt; collection only to admins.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the other hand, materialized views come into play when performance is key, especially for reads.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Speeding up Reads&lt;/strong&gt;: If you have dashboards or analytics hitting the database with the same heavy aggregations over and over, pre-calculating results in a materialized view makes those reads lightning fast.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Expensive Aggregations&lt;/strong&gt;: Some aggregations just take a long time and use lots of resources. Running them once and storing the result is way more efficient if the data doesn't need to be absolutely live.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Denormalized Data&lt;/strong&gt;: Perfect when you need data structured in a specific format, often combining data from multiple collections.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Implement a MongoDB View?
&lt;/h2&gt;

&lt;p&gt;Alright, let's make a view. It's pretty straightforward.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a View Using MongoDB Shell
&lt;/h3&gt;

&lt;p&gt;Say you have a &lt;code&gt;users&lt;/code&gt; collection and just want a view of the active ones.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// Connect to your database first
// Example: use my_database

db.createView&lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;"active_users_view"&lt;/span&gt;,  // The name of your new view
  &lt;span class="s2"&gt;"users"&lt;/span&gt;,              // The &lt;span class="nb"&gt;source &lt;/span&gt;collection
  &lt;span class="o"&gt;[&lt;/span&gt;                     // The aggregation pipeline
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$match&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt; status: &lt;span class="s2"&gt;"active"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; 
  &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can query it like a regular collection: &lt;code&gt;db.active_users_view.find()&lt;/code&gt; and you'll only get users with &lt;code&gt;status: "active"&lt;/code&gt;. MongoDB runs that &lt;code&gt;$match&lt;/code&gt; pipeline every time you query the view.&lt;/p&gt;

&lt;p&gt;You could even add &lt;code&gt;$group&lt;/code&gt; stages or use cool pipeline stages like &lt;a href="https://mayallo.com/mongodb-facet/" rel="noopener noreferrer"&gt;&lt;code&gt;$facet&lt;/code&gt;&lt;/a&gt; for multi-faceted results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a View Using MongoDB Driver (With Node.js)
&lt;/h3&gt;

&lt;p&gt;Say you want to create a script to create a view programmatically, you can do the following:&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MONGODB_URI&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;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DATABASE_NAME&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;active_users_view&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;viewOn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;pipeline&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;$match&lt;/span&gt;&lt;span class="p"&gt;:&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;active&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;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same functionality as before.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating or Modifying a View
&lt;/h3&gt;

&lt;p&gt;MongoDB views are immutable. You can't &lt;em&gt;alter&lt;/em&gt; an existing view's definition directly. What do you do?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Drop and Recreate&lt;/strong&gt;: The most common way.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;db.active_users_view.drop&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
// Now create it again with the new definition 
db.createView&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"active_users_view"&lt;/span&gt;, &lt;span class="s2"&gt;"users"&lt;/span&gt;, &lt;span class="o"&gt;[&lt;/span&gt; /&lt;span class="k"&gt;*&lt;/span&gt; new pipeline &lt;span class="k"&gt;*&lt;/span&gt;/ &lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Versioning&lt;/strong&gt;: Create a new view with a version number (e.g., &lt;code&gt;active_users_v2&lt;/code&gt;) and update your application code to use the new one. You can drop the old one later.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to Implement a MongoDB Materialized View?
&lt;/h2&gt;

&lt;p&gt;MongoDB doesn't have a built-in &lt;code&gt;CREATE MATERIALIZED VIEW&lt;/code&gt; command like some SQL databases (not yet, anyway). So we have to implement it manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep in mind,&lt;/strong&gt; when we talk about Materialized Views, the create operation is the same as the refresh operation. Because the refresh operation needs an existing collection, and if it is not there, it will create a new one. So they are not separate.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Create/Refresh with Aggregation (&lt;code&gt;$out&lt;/code&gt;)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the simplest. Run an aggregation pipeline and tell it to write the results to a new collection using the &lt;code&gt;$out&lt;/code&gt; stage.&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;aggregate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="na"&gt;$match&lt;/span&gt;&lt;span class="p"&gt;:&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Only completed orders&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="na"&gt;$group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$customerId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Group by customer&lt;/span&gt;
      &lt;span class="na"&gt;totalSpent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$sum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$amount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Sum their order amounts&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;$out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;customer_spending_mv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// Write results to this collection (materialized view)&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;Now you have a &lt;code&gt;customer_spending_mv&lt;/code&gt; collection, and, you can query it like this &lt;code&gt;db.customer_spending_mv.find()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: &lt;code&gt;$out&lt;/code&gt; &lt;em&gt;replaces&lt;/em&gt; the entire output collection every time it runs. If the aggregation fails mid-way, you might lose the collection temporarily. Good for infrequent updates or simple use.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Create/Refresh with Aggregation (&lt;code&gt;$merge&lt;/code&gt;)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Run an aggregation and merge the results into an existing collection. This is more flexible; you can update existing documents, insert new ones, or even fail the operation based on matching conditions. Better for incremental updates.&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;aggregate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="na"&gt;$match&lt;/span&gt;&lt;span class="p"&gt;:&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Only completed orders&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="na"&gt;$group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$customerId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Group by customer&lt;/span&gt;
      &lt;span class="na"&gt;totalSpent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$sum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$amount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Sum their order amounts&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;$merge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;into&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;customer_spending_mv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// The target collection&lt;/span&gt;
      &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Field to match documents on&lt;/span&gt;
      &lt;span class="na"&gt;whenMatched&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;replace&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// What to do if a document matches (update it)&lt;/span&gt;
      &lt;span class="na"&gt;whenNotMatched&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;insert&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// What to do if no document matches (insert it)&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;ol&gt;
&lt;li&gt; &lt;strong&gt;Completely Manual Create/Refresh&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We knew that the materialized view is just another collection, right? Then, we can write a custom script that queries the source data and updates the target materialized view collection. Makes sense? Gives you maximum control but requires more effort as it is your responsibility to keep both collections in sync.&lt;/p&gt;

&lt;h3&gt;
  
  
  On-Demand vs. Incremental Refresh Strategies
&lt;/h3&gt;

&lt;p&gt;Since materialized views store data snapshots, you have to decide how to keep them updated.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;On-Demand Refresh:&lt;/strong&gt; You update the view whenever you need to, maybe manually or via an API call. Simple, but data can get quite stale. Useful if updates are infrequent or data changes predictably.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Scheduled Refresh (Batch):&lt;/strong&gt; Use a scheduler (like &lt;code&gt;cron&lt;/code&gt; or &lt;a href="https://www.mongodb.com/docs/atlas/app-services/triggers/scheduled-triggers/" rel="noopener noreferrer"&gt;MongoDB Atlas Scheduled Triggers&lt;/a&gt;) to run your &lt;code&gt;$out&lt;/code&gt; or &lt;code&gt;$merge&lt;/code&gt; aggregation periodically (e.g., every hour, every night). This is common for reports. Data freshness depends on the schedule frequency.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Incremental Refresh (Near Real-Time):&lt;/strong&gt; Use MongoDB Change Streams. These let you watch for changes (inserts, updates, deletes) in the source collection(s) in real-time. When a change happens, you trigger a small, targeted update to your materialized view collection. This keeps the view much more up-to-date but is more complex to set up and manage and &lt;em&gt;&lt;a href="https://www.mongodb.com/docs/manual/changeStreams/" rel="noopener noreferrer"&gt;it is available only on the replica-set setup&lt;/a&gt;&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choosing the right strategy depends completely on how fresh your data needs to be and how much load the refresh process puts on your system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Benchmark: Views vs Materialized Views
&lt;/h2&gt;

&lt;p&gt;Talking performance is nice, but seeing is believing, right? For that reason, &lt;a href="https://github.com/Mohamed-Mayallo/mongodb-views-vs-materialized-views" rel="noopener noreferrer"&gt;I built a small app&lt;/a&gt; where I have the &lt;code&gt;orders&lt;/code&gt; collection that has tons of documents. And created a View and a Materialized View to measure the query performance of both. Let's see.&lt;/p&gt;

&lt;p&gt;First, run the following commands in sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run setup-db &lt;span class="c"&gt;# setup the `sales` database&lt;/span&gt;
npm run seed-data &lt;span class="c"&gt;# seed the `orders` collection&lt;/span&gt;
npm run create-standard-view &lt;span class="c"&gt;# create the `order_analytics_view` view&lt;/span&gt;
npm run create-materialized-view &lt;span class="c"&gt;# create the `order_analytics_materialized` materialized view&lt;/span&gt;
npm run start &lt;span class="c"&gt;# run the Node.js server&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, open your browser and hit this endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;http://localhost:3000/api/analytics/compare
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This request returns 100 documents for both the View, the Materialized View, and some performance metrics. And technically uses the same aggregation query under the hood.&lt;/p&gt;

&lt;p&gt;Let's have a look at the performance metrics (&lt;em&gt;in my environment&lt;/em&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"performance"&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;"standardView"&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;"queryTimeMs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;274&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"resultCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&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;"materializedView"&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;"queryTimeMs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"resultCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"lastUpdated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2025-04-20T06:19:40.416Z"&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;"comparison"&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;"timeDifferenceMs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;268&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"percentageDifference"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"97.81%"&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;If you noticed the huge gap in performance between both, the Materialized View is &lt;strong&gt;97.81%&lt;/strong&gt; faster than the Standard View, and that's expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Cases For Each Approach
&lt;/h2&gt;

&lt;p&gt;So, when should you pick which?&lt;/p&gt;

&lt;h3&gt;
  
  
  MongoDB Views – Ideal Scenarios
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Role-Based Access&lt;/strong&gt;: Show different data slices to different user roles without complex app logic. Expose &lt;code&gt;limited_user_profile_view&lt;/code&gt; vs full &lt;code&gt;users&lt;/code&gt; collection.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Admin Dashboards (Light Filtering)&lt;/strong&gt;: Simple dashboards that need real-time data but don't involve massive aggregations.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Rapid Prototyping&lt;/strong&gt;: Quickly define a data shape without restructuring collections.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Simplifying Application Queries&lt;/strong&gt;: Hide complex joins (&lt;code&gt;$lookup&lt;/code&gt;) or calculations behind a simple view name.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Materialized Views – Ideal Scenarios
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Analytics Dashboards&lt;/strong&gt;: Dashboards needing fast responses on complex aggregations (e.g., sales summaries, user activity trends). Hourly or daily freshness is often fine.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Heavy Reporting&lt;/strong&gt;: Generating complex reports that would time out or overload the DB if run live. Run the aggregation overnight into a materialized view.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Time-Series Aggregations&lt;/strong&gt;: Summarizing large amounts of time-series data (e.g., daily sensor readings into monthly averages).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Denormalization for Microservices&lt;/strong&gt;: Create a specialized, denormalized collection (your materialized view) optimized for a specific microservice's read patterns, fed from other source collections/services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmayallo.com%2Fwp-content%2Fuploads%2F2025%2F04%2Flaurin-steffens-IVGZ6NsmyBI-unsplash-1024x576.avif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmayallo.com%2Fwp-content%2Fuploads%2F2025%2F04%2Flaurin-steffens-IVGZ6NsmyBI-unsplash-1024x576.avif" alt="FAQ for MongoDB Views or Materialized Views: When to Use?" width="1024" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions (FAQ)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q1: Can you create an index on a MongoDB View?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No, you cannot create indexes directly on a MongoDB View itself. Performance depends on the indexes present on the underlying source collection(s) that the view's aggregation pipeline uses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2: Can you update data through a MongoDB View?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No, MongoDB Views are strictly read-only. You cannot perform insert, update, or delete operations through a view. You must modify the data in the base collection(s).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3: How often should I refresh a Materialized View in MongoDB?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
It depends entirely on your application's tolerance for stale data versus the overhead of the refresh process. It could be every few minutes, hourly, daily, or even weekly. Analyze your specific needs. For near real-time, consider Change Streams, but that's much more complex.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4: Does using &lt;code&gt;$out&lt;/code&gt; or &lt;code&gt;$merge&lt;/code&gt; lock the source collection during materialized view refresh?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The aggregation pipeline reads from the source collection(s), which will acquire the necessary read locks or yield like any other aggregation. The &lt;code&gt;$out&lt;/code&gt; stage briefly acquires an exclusive lock on the &lt;em&gt;destination&lt;/em&gt; collection while replacing it. &lt;code&gt;$merge&lt;/code&gt; acquires locks on the &lt;em&gt;destination&lt;/em&gt; collection as it performs writes/updates. The impact on the &lt;em&gt;source&lt;/em&gt; collection is primarily the read load of the aggregation itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q5: Is there a size limit for MongoDB Views?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No, because views don't store data. However, the aggregation pipeline defining the view has limits (e.g., 100MB memory limit by default unless &lt;code&gt;allowDiskUse: true&lt;/code&gt; is specified, though this option isn't always usable in the &lt;em&gt;first&lt;/em&gt; stage of a view definition). The performance will degrade significantly if the view's query processes massive amounts of data without good indexing on the base collection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Okay. We covered a lot.&lt;/p&gt;

&lt;p&gt;We learned that a Standard View is a saved query and a Materialized View is a saved collection.&lt;br&gt;&lt;br&gt;
And, as usual, everything is a trade-off:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Standard Views = Simplicity + Real-time Data (but potentially slow reads)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Materialized Views = Fast Reads (but Complexity + Stale Data + Storage Costs)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, pick the tool that fits the job. Don't over-engineer if a simple view works, but don't shy away from materialized views when you really need that speed boost.&lt;/p&gt;

&lt;p&gt;And keep in mind, you don't always have to choose just one. Sometimes, a mix is best.&lt;/p&gt;

&lt;h2&gt;
  
  
  Think about it
&lt;/h2&gt;

&lt;p&gt;If you enjoyed this article, I’d truly appreciate it if you could share it—it really motivates me to keep creating more helpful content!&lt;/p&gt;

&lt;p&gt;If you’re interested in exploring more, check out these articles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/mongodb-gridfs/" rel="noopener noreferrer"&gt;&lt;strong&gt;MongoDB GridFS Made simple&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/isolation-levels-sql-server/" rel="noopener noreferrer"&gt;&lt;strong&gt;Isolation Levels In SQL Server With Examples&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://mayallo.com/mongodb-facet/" rel="noopener noreferrer"&gt;&lt;strong&gt;Mastering MongoDB $facet for Powerful Aggregations&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for sticking with me until the end—I hope you found this article valuable and enjoyable!&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>nosql</category>
      <category>database</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
