<?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: Utkarsh Bansal</title>
    <description>The latest articles on DEV Community by Utkarsh Bansal (@utkarshbansal01).</description>
    <link>https://dev.to/utkarshbansal01</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%2F1663345%2F3c1e05b6-b482-4760-aabe-67fa35a17b9e.jpeg</url>
      <title>DEV Community: Utkarsh Bansal</title>
      <link>https://dev.to/utkarshbansal01</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/utkarshbansal01"/>
    <language>en</language>
    <item>
      <title>**What's the most over-engineered AI solution you've seen for a problem a linter already solves?**
 We added AI to write code. Then AI to review code. Then AI to verify code. The thing that actually reduced incidents? ESLint.</title>
      <dc:creator>Utkarsh Bansal</dc:creator>
      <pubDate>Fri, 12 Jun 2026 18:31:01 +0000</pubDate>
      <link>https://dev.to/utkarshbansal01/whats-the-most-over-engineered-ai-solution-youve-seen-for-a-problem-a-linter-already-48b5</link>
      <guid>https://dev.to/utkarshbansal01/whats-the-most-over-engineered-ai-solution-youve-seen-for-a-problem-a-linter-already-48b5</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://dev.to/utkarshbansal01/how-eslint-actually-works-the-quality-gate-behind-modern-javascript-50nk" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4q01nv9t9kq2xj2trp6.png" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://dev.to/utkarshbansal01/how-eslint-actually-works-the-quality-gate-behind-modern-javascript-50nk" rel="noopener noreferrer" class="c-link"&gt;
            How ESLint Actually Works: The Quality Gate Behind Modern JavaScript - DEV Community
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            A few days ago, I shared an article:   You Don't Need Another Agent. You Need a Linter.   Then I did...
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j7kvp660rqzt99zui8e.png"&gt;
          dev.to
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>discuss</category>
      <category>javascript</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>How ESLint Actually Works: The Quality Gate Behind Modern JavaScript</title>
      <dc:creator>Utkarsh Bansal</dc:creator>
      <pubDate>Fri, 12 Jun 2026 12:37:30 +0000</pubDate>
      <link>https://dev.to/utkarshbansal01/how-eslint-actually-works-the-quality-gate-behind-modern-javascript-50nk</link>
      <guid>https://dev.to/utkarshbansal01/how-eslint-actually-works-the-quality-gate-behind-modern-javascript-50nk</guid>
      <description>&lt;p&gt;A few days ago, I shared an article:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://dev.to/utkarsh_bansal_01/you-dont-need-another-agent-you-need-a-linter-1b9i"&gt;You Don't Need Another Agent. You Need a Linter.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then I did what I do with anything I write: shared it around — a few publications, a few channels.&lt;/p&gt;

&lt;p&gt;Two reasons:&lt;/p&gt;

&lt;p&gt;First, feedback. I'd genuinely rather get roasted and fix my blind spots than stay comfortable and wrong.&lt;/p&gt;

&lt;p&gt;Second, let's be honest: reach.&lt;br&gt;
Every writer enjoys seeing a few more views.&lt;/p&gt;

&lt;p&gt;Most of the responses were positive.&lt;/p&gt;

&lt;p&gt;One wasn't.&lt;/p&gt;

&lt;p&gt;A publication rejected it with the reason:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;LOW_QUALITY&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fair enough.&lt;/p&gt;

&lt;p&gt;It means there's room for improvement.&lt;/p&gt;

&lt;p&gt;Funny enough, my caffeinated 1 AM brain disagreed.&lt;/p&gt;

&lt;p&gt;Then it did what every developer does when someone says "this isn't good enough."&lt;/p&gt;

&lt;p&gt;It took that personally.&lt;/p&gt;

&lt;p&gt;So I went back and reread the article.&lt;/p&gt;

&lt;p&gt;And after the initial ego check, I realized something serious:&lt;/p&gt;

&lt;p&gt;The article talked in detail about ESLint, why it matters more in an AI-assisted world than ever.&lt;/p&gt;

&lt;p&gt;What it did not do was answer the question that actually matters:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is ESLint, how does it work, and why has half the JavaScript ecosystem quietly built its quality process around it?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So let's fix that.&lt;/p&gt;

&lt;p&gt;Now, this isn't a sequel to my last piece about untangling vibe-coded code. It stands on its own — &lt;strong&gt;&lt;em&gt;one thing, done properly&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A complete teardown of ESLint:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What it is&lt;/li&gt;
&lt;li&gt;How it works internally&lt;/li&gt;
&lt;li&gt;Why companies use it as a quality gate&lt;/li&gt;
&lt;li&gt;The different classes of problems it solves&lt;/li&gt;
&lt;li&gt;How plugins work&lt;/li&gt;
&lt;li&gt;How to write your own rules&lt;/li&gt;
&lt;li&gt;Where it fails&lt;/li&gt;
&lt;li&gt;Why it still beats many AI-based review systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fair warning.&lt;/p&gt;

&lt;p&gt;This article is going to be technical.&lt;/p&gt;

&lt;p&gt;There will be syntax trees.&lt;/p&gt;

&lt;p&gt;There will be compiler concepts.&lt;/p&gt;

&lt;p&gt;There will be enough JavaScript internals to make frontend developers slightly uncomfortable.&lt;/p&gt;

&lt;p&gt;I'll try my best to keep it readable not letting it turn into another manual - which nobody finishes.&lt;/p&gt;

&lt;p&gt;Let's start with the question most people never ask.&lt;/p&gt;
&lt;h2&gt;
  
  
  What Is ESLint Actually Doing?
&lt;/h2&gt;

&lt;p&gt;Most developers describe ESLint like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It checks code for mistakes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Technically true. Also completely useless.&lt;/p&gt;

&lt;p&gt;That's like describing a car as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It helps you move.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The interesting part is &lt;strong&gt;&lt;em&gt;how?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUsers&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="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/users&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;With the right rules on, ESLint can tell us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;axios&lt;/code&gt; is imported and never used&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fetch&lt;/code&gt; is being used&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getUsers&lt;/code&gt; exists&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getUsers&lt;/code&gt; is never called&lt;/li&gt;
&lt;li&gt;there are no syntax errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But how?&lt;/p&gt;

&lt;p&gt;The answer is that &lt;strong&gt;&lt;em&gt;ESLint never reads code as text&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The first thing it does is destroy your beautiful source code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 1: Your Code Stops Being Code
&lt;/h2&gt;

&lt;p&gt;The moment ESLint sees a file, it passes it through a parser.&lt;/p&gt;

&lt;p&gt;The parser converts your code into something called an Abstract Syntax Tree (AST).&lt;/p&gt;

&lt;p&gt;Your code:&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;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;becomes something closer to:&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VariableDeclaration"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"const"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"declarations"&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;"id"&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;"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;"answer"&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;"init"&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;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&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;p&gt;Notice what's missing.&lt;/p&gt;

&lt;p&gt;Formatting. Spacing. Comments. Indentation.&lt;/p&gt;

&lt;p&gt;The parser doesn't care. The AST only cares about meaning.&lt;/p&gt;

&lt;p&gt;To ESLint, your source code isn't text anymore.&lt;/p&gt;

&lt;p&gt;It's a tree.&lt;/p&gt;

&lt;p&gt;Literally. That same &lt;code&gt;const answer = 42&lt;/code&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VariableDeclaration · const
└─ VariableDeclarator
   ├─ Identifier · "answer"
   └─ Literal · 42
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The JSON above and this tree are the same thing. One's just easier to look at.&lt;/p&gt;

&lt;p&gt;And every lint rule is basically a tree inspector.&lt;/p&gt;

&lt;p&gt;That's the core idea:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source code
   ↓
Parser
   ↓
AST
   ↓
Rules inspect nodes
   ↓
Reports / warnings / errors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Rules Walk The Tree
&lt;/h2&gt;

&lt;p&gt;Every ESLint rule is a visitor.&lt;/p&gt;

&lt;p&gt;It walks through the nodes inside the AST and asks questions.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;debug&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;produces a node that looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CallExpression
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;no-console&lt;/code&gt; rule simply visits every &lt;code&gt;CallExpression&lt;/code&gt; and asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is this a console call?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If yes.&lt;/p&gt;

&lt;p&gt;Report error.&lt;/p&gt;

&lt;p&gt;That's it.&lt;/p&gt;

&lt;p&gt;No AI. No embeddings. No vector database.&lt;/p&gt;

&lt;p&gt;Just deterministic tree traversal.&lt;/p&gt;

&lt;p&gt;Computer science doing computer science things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Is More Powerful Than It Sounds
&lt;/h2&gt;

&lt;p&gt;Most people hear "static analysis" and immediately think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So... it catches semicolons?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;Semicolons are the least interesting thing ESLint does.&lt;/p&gt;

&lt;p&gt;Let's look at the categories.&lt;/p&gt;

&lt;h3&gt;
  
  
  Category 1: Correctness
&lt;/h3&gt;

&lt;p&gt;These rules catch code that is probably wrong.&lt;/p&gt;

&lt;p&gt;A function that doesn't exist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An assignment hiding inside a condition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &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="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A promise nobody awaited:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;promiseFunction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are not style issues. These are bugs.&lt;/p&gt;

&lt;p&gt;The code may compile. It may even pass tests.&lt;/p&gt;

&lt;p&gt;But eventually somebody is getting paged at 2 AM.&lt;/p&gt;

&lt;h3&gt;
  
  
  Category 2: Dead Code
&lt;/h3&gt;

&lt;p&gt;AI loves dead code. Humans create it too. AI just does it faster.&lt;/p&gt;

&lt;p&gt;An import that's never used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;lodash&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A function nobody calls anymore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;oldImplementation&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;One abandoned experiment later, and your repository becomes an archaeological site.&lt;/p&gt;

&lt;p&gt;Dead code increases bundle size, maintenance cost, and confusion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The cheapest bug is the code that doesn't exist.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ESLint helps make that happen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Category 3: Security
&lt;/h3&gt;

&lt;p&gt;This is where people start underestimating linters.&lt;/p&gt;

&lt;p&gt;Consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No. Just no.&lt;/p&gt;

&lt;p&gt;Or:&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;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also no.&lt;/p&gt;

&lt;p&gt;A decent security-focused lint setup can stop entire classes of vulnerabilities before the code ever reaches production.&lt;/p&gt;

&lt;p&gt;Not because it's intelligent.&lt;/p&gt;

&lt;p&gt;Because it recognizes dangerous patterns.&lt;/p&gt;

&lt;p&gt;And dangerous patterns repeat. A lot.&lt;/p&gt;

&lt;h3&gt;
  
  
  Category 4: Performance
&lt;/h3&gt;

&lt;p&gt;Some rules exist purely because developers keep making the same expensive mistakes.&lt;/p&gt;

&lt;p&gt;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="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&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="o"&gt;!==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;can become 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="nx"&gt;array&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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tiny improvement.&lt;/p&gt;

&lt;p&gt;Tiny improvement.&lt;/p&gt;

&lt;p&gt;Tiny improvement.&lt;/p&gt;

&lt;p&gt;Now repeat it across a million lines of code, and you've quietly compressed years of engineering experience into a config file.&lt;/p&gt;

&lt;p&gt;That's what lint rules really are.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Institutional memory&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Real Superpower: Quality Gates
&lt;/h2&gt;

&lt;p&gt;The biggest mistake teams make is treating ESLint like a suggestion.&lt;/p&gt;

&lt;p&gt;A linter running in your editor is nice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A linter blocking merges is transformative.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The moment ESLint becomes part of CI, it stops being advice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It becomes policy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The workflow changes from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hopefully somebody notices the bug in review.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The code physically cannot merge.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's a completely different game.&lt;/p&gt;

&lt;p&gt;Good engineering isn't about creating perfect developers.&lt;/p&gt;

&lt;p&gt;It's about creating systems where common mistakes cannot survive.&lt;/p&gt;

&lt;p&gt;ESLint is one of those systems.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Developer writes code
   ↓
Editor lint shows warnings
   ↓
PR created
   ↓
CI runs lint
   ↓
Pass → merge
Fail → fix before merge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Community Plugins Already Solved Half Your Problems
&lt;/h2&gt;

&lt;p&gt;Here's the part most developers miss. &lt;/p&gt;

&lt;p&gt;ESLint is a rule engine.&lt;/p&gt;

&lt;p&gt;It parses code, walks the AST, runs rules, reports violations, and that's basically the entire core.&lt;/p&gt;

&lt;p&gt;The real power comes from everything built on top of it: plugins, shared rule sets, and years of accumulated engineering knowledge.&lt;/p&gt;

&lt;p&gt;Need to find unused imports?&lt;/p&gt;

&lt;p&gt;There's a plugin. &lt;code&gt;eslint-plugin-unused-imports&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Need TypeScript-aware analysis?&lt;/p&gt;

&lt;p&gt;There's a plugin. &lt;code&gt;@typescript-eslint&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Need accessibility checks for your components?&lt;/p&gt;

&lt;p&gt;There's a plugin. &lt;code&gt;eslint-plugin-jsx-a11y&lt;/code&gt; or &lt;code&gt;eslint-plugin-vuejs-accessibility&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Need to catch dangerous security patterns?&lt;/p&gt;

&lt;p&gt;There's a plugin. &lt;code&gt;eslint-plugin-security&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Need to enforce architectural boundaries between layers?&lt;/p&gt;

&lt;p&gt;Believe it or not, there's a plugin for that too. &lt;code&gt;eslint-plugin-boundaries.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You don't have to write any of this yourself.&lt;/p&gt;

&lt;p&gt;Thousands of developers have already spent years turning common mistakes into reusable rules.&lt;/p&gt;

&lt;p&gt;A few common examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;eslint-plugin-unused-imports&lt;/code&gt; — dead imports and variables&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;eslint-plugin-import&lt;/code&gt; — circular dependencies and broken paths&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@typescript-eslint&lt;/code&gt; — type-aware correctness rules&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;eslint-plugin-jsx-a11y&lt;/code&gt; / &lt;code&gt;eslint-plugin-vuejs-accessibility&lt;/code&gt; — accessibility&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;eslint-plugin-promise&lt;/code&gt; — dropped awaits and async mistakes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;eslint-plugin-security&lt;/code&gt; — dangerous patterns like &lt;code&gt;eval&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;eslint-plugin-boundaries&lt;/code&gt; — architectural layer rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the mental shift.&lt;/p&gt;

&lt;p&gt;Most people think ESLint is one tool with a bunch of built-in rules.&lt;/p&gt;

&lt;p&gt;It's closer to a platform.&lt;/p&gt;

&lt;p&gt;A small, stable engine that lets an entire ecosystem contribute knowledge.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  eslint-plugin-import     @typescript-eslint     your local rules
   (cycles, dead code)     (type-aware checks)     (team gates)
            │                      │                      │
            └──────────────────────┼──────────────────────┘
                                   ▼
            ┌──────────────────────────────────────────┐
            │                ESLint core                 │
            │     parse → walk the AST → run → report     │
            └──────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's why ESLint has survived for so long.&lt;/p&gt;

&lt;p&gt;The core doesn't need to know about &lt;code&gt;React&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Or &lt;code&gt;Vue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Or &lt;code&gt;TypeScript&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Or whatever framework we'll all be rewriting our applications in next year.&lt;/p&gt;

&lt;p&gt;The engine stays the same.&lt;/p&gt;

&lt;p&gt;The ecosystem keeps growing.&lt;/p&gt;

&lt;p&gt;The core never changes. The rules feeding into it are infinite.&lt;/p&gt;

&lt;p&gt;And eventually you realize something interesting:&lt;/p&gt;

&lt;p&gt;Most teams don't need more tooling.&lt;/p&gt;

&lt;p&gt;They just need to enable the plugins that already exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  When The Defaults Aren't Enough: Write Your Own Rule
&lt;/h2&gt;

&lt;p&gt;Now for the fun part — the part that makes ESLint feel less like a tool and more like a system.&lt;/p&gt;

&lt;p&gt;Suppose your company has a design system. And somebody keeps committing raw colors:&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;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#FF0000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;instead of:&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;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can complain. You can review every PR. Or you can automate the complaint.&lt;/p&gt;

&lt;p&gt;Here's the entire rule:&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;// rules/no-raw-color.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="p"&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="s2"&gt;problem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;rawColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Use a design token, not a raw hex like '{{value}}'.&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="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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="c1"&gt;// the walker hands you every string literal; you keep the ones that look like hex&lt;/span&gt;
      &lt;span class="nc"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&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;typeof&lt;/span&gt; &lt;span class="nx"&gt;node&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="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="sr"&gt;/^#&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;0-9a-f&lt;/span&gt;&lt;span class="se"&gt;]{3,6}&lt;/span&gt;&lt;span class="sr"&gt;$/i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&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="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;report&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;messageId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rawColor&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;node&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="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;That's it. No npm package, no publishing. Flat config lets you wire a local rule in directly, and ESLint's built-in &lt;code&gt;RuleTester&lt;/code&gt; lets you prove it fires on &lt;code&gt;"#FF0000"&lt;/code&gt; and stays quiet on &lt;code&gt;tokens.error&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A custom ESLint rule is usually less code than the Slack argument it prevents.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's the real secret.&lt;/p&gt;

&lt;p&gt;The best engineering teams don't repeatedly solve the same problem.&lt;/p&gt;

&lt;p&gt;They automate it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Every bug becomes a rule. Every rule becomes institutional knowledge. Every future developer benefits.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Human. Or AI. Doesn't matter.&lt;/p&gt;

&lt;p&gt;The gate treats everybody equally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where ESLint Fails
&lt;/h2&gt;

&lt;p&gt;Now, before somebody accuses me of turning ESLint into a religion — it has limits.&lt;/p&gt;

&lt;p&gt;ESLint cannot tell:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if your architecture is good&lt;/li&gt;
&lt;li&gt;if your business logic is correct&lt;/li&gt;
&lt;li&gt;if the feature should even exist&lt;/li&gt;
&lt;li&gt;if your product manager had a terrible idea&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those remain human problems.&lt;/p&gt;

&lt;p&gt;Static analysis sees structure. Not intent.&lt;/p&gt;

&lt;p&gt;A green lint report does not mean correct software.&lt;/p&gt;

&lt;p&gt;It means your code survived a specific set of inspections.&lt;/p&gt;

&lt;p&gt;Nothing more. Nothing less.&lt;/p&gt;

&lt;h2&gt;
  
  
  So Why Am I Still Talking About ESLint In The Age Of AI?
&lt;/h2&gt;

&lt;p&gt;Because every week I see somebody proposing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI review agents&lt;/li&gt;
&lt;li&gt;AI architecture agents&lt;/li&gt;
&lt;li&gt;AI quality agents&lt;/li&gt;
&lt;li&gt;AI code verification agents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And half the time, they're trying to solve problems ESLint solved years ago.&lt;/p&gt;

&lt;p&gt;Before building another agent, ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can a deterministic static analysis tool already solve this?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because if the answer is yes, the boring tool is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;faster&lt;/li&gt;
&lt;li&gt;cheaper&lt;/li&gt;
&lt;li&gt;reproducible&lt;/li&gt;
&lt;li&gt;and it doesn't hallucinate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The boring solution often wins.&lt;/p&gt;

&lt;p&gt;Not because it's exciting. Because it works.&lt;/p&gt;

&lt;p&gt;And software engineering eventually rewards whatever keeps production alive — even if it was invented twenty years ago.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;The most important thing I learned from AI-assisted development wasn't how powerful AI is.&lt;/p&gt;

&lt;p&gt;It was how valuable boring tooling remains.&lt;/p&gt;

&lt;p&gt;ESLint isn't glamorous. Nobody posts screenshots of lint checks on LinkedIn. Nobody raises venture capital for a missing-semicolon detector.&lt;/p&gt;

&lt;p&gt;But every large JavaScript codebase eventually discovers the same truth.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It parses code. It walks trees. It applies rules. It reports violations. That sounds humble — but the impact compounds: it catches bugs early, enforces standards, protects architecture, scales institutional memory, and keeps bad code from sneaking through the door.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And unlike the rest of us, it never gets tired.&lt;/p&gt;

&lt;p&gt;The cheapest reviewer on your team is still a linter.&lt;/p&gt;

&lt;p&gt;If you still think of ESLint as a semicolon cop, you're missing most of the point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It was never about the semicolons.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>architecture</category>
      <category>learning</category>
    </item>
    <item>
      <title>What's the most over-engineered AI solution you've seen for a problem a linter already solves?
We added AI to write code. Then AI to review code. Then AI to verify code.
The thing that actually reduced incidents? ESLint.</title>
      <dc:creator>Utkarsh Bansal</dc:creator>
      <pubDate>Wed, 10 Jun 2026 15:54:26 +0000</pubDate>
      <link>https://dev.to/utkarshbansal01/whats-the-most-over-engineered-ai-solution-youve-seen-for-a-problem-a-linter-already-solves-we-1o55</link>
      <guid>https://dev.to/utkarshbansal01/whats-the-most-over-engineered-ai-solution-youve-seen-for-a-problem-a-linter-already-solves-we-1o55</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://dev.to/utkarshbansal01/you-dont-need-another-agent-you-need-a-linter-1b9i" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8j3zlt8lcf5gzmdmvsx.png" height="450" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://dev.to/utkarshbansal01/you-dont-need-another-agent-you-need-a-linter-1b9i" rel="noopener noreferrer" class="c-link"&gt;
            You Don't Need Another Agent. You Need a Linter. - DEV Community
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            In my last post I complained — a lot — about vibe code and the beautiful disaster it left...
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j7kvp660rqzt99zui8e.png" width="300" height="299"&gt;
          dev.to
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>discuss</category>
      <category>javascript</category>
      <category>tooling</category>
    </item>
    <item>
      <title>You Don't Need Another Agent. You Need a Linter.</title>
      <dc:creator>Utkarsh Bansal</dc:creator>
      <pubDate>Wed, 10 Jun 2026 15:49:20 +0000</pubDate>
      <link>https://dev.to/utkarshbansal01/you-dont-need-another-agent-you-need-a-linter-1b9i</link>
      <guid>https://dev.to/utkarshbansal01/you-dont-need-another-agent-you-need-a-linter-1b9i</guid>
      <description>&lt;p&gt;In my last post I complained — a lot — about vibe code and the beautiful disaster it left behind.&lt;/p&gt;

&lt;p&gt;Now, I'm not here just to complain. There were a lot of learning opportunities too, like how to handle legacy / vibe code. Because at the end of the day, both are the same: no one knows how they work, but somehow they keep working. Touching them is like defusing a bomb — you never know how your change might cascade and break the core logic.&lt;/p&gt;

&lt;p&gt;The good news is that vibe code is much simpler than legacy. AI, in all its glory, tries to write perfect-looking code — proper function names, comments, the works — not like legacy code where a single function runs 500 lines, with spaghetti names all over that make no sense and comments that are out of date.&lt;/p&gt;

&lt;p&gt;And that makes it something I can actually handle. I still don't have a perfect, step-by-step playbook — but I've got pieces.&lt;/p&gt;

&lt;p&gt;The first one. The cheapest and the oldest one. The one the industry solved decades ago and the whole "AI built my app in a day" crowd somehow forgot exists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A linter.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, you heard me right. A linter. ESLint.&lt;/p&gt;

&lt;p&gt;Most people who've been in this industry already know it. It's the most boring, reliable tool in the box.&lt;/p&gt;

&lt;p&gt;But in an era where the answer to every problem is "add another AI," it's worth saying out loud why the boring tool still wins.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a linter actually is
&lt;/h2&gt;

&lt;p&gt;If you vibe-coded your way into this world, or you're new to web dev in general and have never heard the word "lint", here's the honest version.&lt;/p&gt;

&lt;p&gt;A linter is a set of rules you add to your repo. It reads your code without running it, checks it against those rules, and flags everything that's broken, sloppy, or about to bite you in production.&lt;/p&gt;

&lt;p&gt;The detail people get wrong: it's not a &lt;code&gt;grep&lt;/code&gt; for bad words.&lt;/p&gt;

&lt;p&gt;A real linter parses your code into a syntax tree and actually reasons about its structure — what's imported, what's called, what's reachable, what types flow where.&lt;/p&gt;

&lt;p&gt;That's why a rule like &lt;code&gt;no-unused-vars&lt;/code&gt; can tell "you imported this and never used it" apart from "you used this without importing it."&lt;/p&gt;

&lt;p&gt;It's also why &lt;code&gt;eslint-plugin-unicorn&lt;/code&gt; can quietly rewrite &lt;code&gt;array.indexOf(x) !== -1&lt;/code&gt; into &lt;code&gt;array.includes(x)&lt;/code&gt; (&lt;code&gt;unicorn/prefer-includes&lt;/code&gt;), or flag a &lt;code&gt;new Array(...)&lt;/code&gt; call that's going to bite you — without ever executing a single line.&lt;/p&gt;

&lt;p&gt;Three properties matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It doesn't run your code.&lt;/strong&gt; No side effects, no flaky network, no "works on my machine."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's deterministic.&lt;/strong&gt; Same code in, same result out, every single time. No temperature, no vibes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It costs nothing.&lt;/strong&gt; No tokens. No API bill. It runs in seconds on a laptop or a CI box.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In 2026, that last one is the whole argument.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters more than it used to
&lt;/h2&gt;

&lt;p&gt;We have AI to write code. AI to review code. AI to verify code. Agents stacked on agents, each one quietly spending tokens to do something a free tool already did better.&lt;/p&gt;

&lt;p&gt;And honestly? Most of those agents are re-solving problems that were solved long before "agent" meant what it means today.&lt;/p&gt;

&lt;p&gt;You do not need a language model to notice that you left a debug log in production (&lt;code&gt;no-console&lt;/code&gt;). Or imported a module you never used (&lt;code&gt;unused-imports/no-unused-imports&lt;/code&gt;). Or wrote a function nobody calls (&lt;code&gt;knip&lt;/code&gt;). Or forgot to &lt;code&gt;await&lt;/code&gt; a promise (&lt;code&gt;@typescript-eslint/no-floating-promises&lt;/code&gt;). Or made two files import each other in a circle (&lt;code&gt;import/no-cycle&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;A linter catches every one of those instantly, deterministically, for free — before any AI even wakes up.&lt;/p&gt;

&lt;p&gt;So before you bolt another agent onto your pipeline, ask the boring question: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does the free, battle-tested tool already do this?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Usually it does.&lt;/p&gt;

&lt;p&gt;Use what already exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  A linter is a &lt;strong&gt;Quality Gate&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is the real reason linters matter. Whether you're a big company or a freelancer just starting out.&lt;/p&gt;

&lt;p&gt;A linter is a quality gate. A line in the sand that says: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This code does not get in unless it clears the bar.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Where I work, we wired this straight into the pull-request flow. A check a PR &lt;em&gt;has&lt;/em&gt; to pass before it can merge.&lt;/p&gt;

&lt;p&gt;Not a suggestion. Not "we'll clean it up later." A hard gate on the merge button.&lt;/p&gt;

&lt;p&gt;The result was the kind of number that sounds made up until you live it: production issues and bad merges dropped by roughly 80%.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Magic?&lt;/strong&gt; No.&lt;/p&gt;

&lt;p&gt;Most of our incidents were the same boring handful — an unhandled promise that swallowed an error, a stray debug log left in, a circular import that only broke in prod. The gate caught every one of them at the door — we just stopped letting broken code through.&lt;/p&gt;

&lt;p&gt;That's the whole trick. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A gate doesn't make anyone smarter. It just raises the floor.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A tip if you're at a big company: when you introduce the ESLint check, you'll hear a lot of pushback from devs — especially at a startup or midsize company. So be ready for a fight, and roll it out gradually: a warning gate first, then an error gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  It doesn't stop at "missing semicolon"
&lt;/h2&gt;

&lt;p&gt;Here's the common misconception people hit when they first add ESLint and see all those errors: "this thing is bad, it just nags me like my annoying brother." That's a huge underestimation.&lt;/p&gt;

&lt;p&gt;Once you treat the linter as a real gate instead of a nag, you can teach it your specific mistakes. And it never forgets them.&lt;/p&gt;

&lt;p&gt;Every painful bug in an AI-assisted codebase is also a &lt;em&gt;pattern&lt;/em&gt;. And patterns are exactly what static analysis is good at.&lt;/p&gt;

&lt;p&gt;A surprising amount of this is one config file away. Modern ESLint flat config plus a few community plugins covers most of it:&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;// eslint.config.js — a starter "quality gate", not a missing-semicolon nag&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;unusedImports&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eslint-plugin-unused-imports&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="nx"&gt;importPlugin&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eslint-plugin-import&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="nx"&gt;unicorn&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eslint-plugin-unicorn&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="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;plugins&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="s2"&gt;unused-imports&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unusedImports&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;import&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;importPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unicorn&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;languageOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// type-aware rules need the TS program, not just the syntax tree&lt;/span&gt;
      &lt;span class="na"&gt;parserOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;projectService&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="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="c1"&gt;// ~100 perf + hidden-bug rules in one line; downgrade the churny ones&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;unicorn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;configs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flat/recommended&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unicorn/filename-case&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="s2"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;// Vue files are PascalCase by convention&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unicorn/prevent-abbreviations&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="s2"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// trips on `ref`, `props`, store names&lt;/span&gt;
      &lt;span class="c1"&gt;// dead code the model left behind — auto-fixable&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unused-imports/no-unused-imports&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="s2"&gt;error&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="s2"&gt;unused-imports/no-unused-vars&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="s2"&gt;warn&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 silent killer (see the circular-deps post) — crank maxDepth up&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;import/no-cycle&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="s2"&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;maxDepth&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="na"&gt;ignoreExternal&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="c1"&gt;// dropped awaits that swallow errors — needs the type info above&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@typescript-eslint/no-floating-promises&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="s2"&gt;error&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="s2"&gt;@typescript-eslint/no-misused-promises&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="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// dynamic code execution: off by default in eslint:recommended, turn them on&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no-eval&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="s2"&gt;error&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="s2"&gt;no-implied-eval&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="s2"&gt;error&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="s2"&gt;no-new-func&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="s2"&gt;error&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="s2"&gt;no-script-url&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="s2"&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="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;That's the floor.&lt;/p&gt;

&lt;p&gt;On top of it, every time something hurt us, we added a rule so it could only hurt us once. Three of them earned their place the hard way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Circular dependencies&lt;/strong&gt; — &lt;code&gt;import/no-cycle&lt;/code&gt; with &lt;code&gt;maxDepth: 10&lt;/code&gt; (the default of &lt;code&gt;1&lt;/code&gt; only sees direct A↔B cycles), backed by &lt;code&gt;dependency-cruiser&lt;/code&gt; for the whole-graph view. AI refactors &lt;em&gt;love&lt;/em&gt; making two modules import each other until the build breaks only in prod. It's the single most common AI-induced bug I've seen — enough that it deserves a post of its own.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dropped awaits&lt;/strong&gt; — &lt;code&gt;@typescript-eslint/no-floating-promises&lt;/code&gt; and &lt;code&gt;no-misused-promises&lt;/code&gt;. A missing &lt;code&gt;await&lt;/code&gt; on a file or network call silently swallows the error, and you find out when a user does. Needs &lt;em&gt;type-aware&lt;/em&gt; linting (&lt;code&gt;parserOptions.projectService&lt;/code&gt;) — the one setup cost worth paying.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The free-wins pack&lt;/strong&gt; — &lt;code&gt;eslint-plugin-unicorn&lt;/code&gt;'s &lt;code&gt;flat/recommended&lt;/code&gt;: ~100 rules for one import. A mix of performance wins (&lt;code&gt;prefer-includes&lt;/code&gt;, &lt;code&gt;prefer-set-has&lt;/code&gt;), real hidden-bug catches (&lt;code&gt;no-array-push-push&lt;/code&gt;, &lt;code&gt;no-thenable&lt;/code&gt;), and some opinionated style. Turn off the churn (&lt;code&gt;unicorn/filename-case&lt;/code&gt;, &lt;code&gt;unicorn/prevent-abbreviations&lt;/code&gt;, &lt;code&gt;unicorn/no-null&lt;/code&gt;) and keep the rest. Best caught-mistakes-to-config ratio you'll find.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rest are quieter, but each one caught something once. Skim them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dead code&lt;/strong&gt; — &lt;code&gt;eslint-plugin-unused-imports&lt;/code&gt; sweeps the imports the model added for an approach it then abandoned (auto-fixed on &lt;code&gt;--fix&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No &lt;code&gt;eval&lt;/code&gt;&lt;/strong&gt; — &lt;code&gt;no-eval&lt;/code&gt;, &lt;code&gt;no-implied-eval&lt;/code&gt;, &lt;code&gt;no-new-func&lt;/code&gt;, &lt;code&gt;no-script-url&lt;/code&gt;. Off by default; zero legit uses, infinite ways for generated code to sneak one in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;XSS sinks&lt;/strong&gt; — &lt;code&gt;vue/no-v-html&lt;/code&gt; / &lt;code&gt;react/no-danger&lt;/code&gt;, plus &lt;code&gt;eslint-plugin-no-unsanitized&lt;/code&gt; for raw &lt;code&gt;innerHTML&lt;/code&gt;. Any HTML injection has to pass through a sanitizer, enforced at lint time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardcoded strings&lt;/strong&gt; — &lt;code&gt;eslint-plugin-i18next&lt;/code&gt;, so the day you add a language nothing's baked into the markup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test hygiene&lt;/strong&gt; — &lt;code&gt;no-focused-tests&lt;/code&gt; as an &lt;strong&gt;error&lt;/strong&gt;, so a stray &lt;code&gt;it.only&lt;/code&gt; can't silently shrink the CI suite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leaked secrets&lt;/strong&gt; — &lt;code&gt;eslint-plugin-no-secrets&lt;/code&gt; flags high-entropy literals that look like committed tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design drift&lt;/strong&gt; (custom) — a ~40-line AST script that fails the build when a raw hex/size/shadow shows up where a named token should be.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layer boundaries&lt;/strong&gt; — &lt;code&gt;eslint-plugin-boundaries&lt;/code&gt; to stop one layer importing another, plus a custom rule forcing risky mutations through a single function.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these is a lesson we only had to learn once.&lt;/p&gt;

&lt;p&gt;After that, the linter remembers it for us. Forever, for free, on every commit, for every contributor — human or AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trick that keeps the gate from being annoying
&lt;/h2&gt;

&lt;p&gt;Most people give up on linting for one reason. They turn on every rule at &lt;code&gt;error&lt;/code&gt; on day one, drown in ten thousand warnings, and rage-quit.&lt;/p&gt;

&lt;p&gt;Don't do that.&lt;/p&gt;

&lt;p&gt;Run new rules &lt;strong&gt;warn-first&lt;/strong&gt;. Let them report without blocking. Get the count to zero on your own schedule. &lt;em&gt;Then&lt;/em&gt; ratchet that rule up to &lt;code&gt;error&lt;/code&gt; so it can never regress.&lt;/p&gt;

&lt;p&gt;Here's the reframe that matters: those warnings aren't a to-do list you owe the linter today. They're a map of where the mines are buried. You freeze the count, stop anyone from planting new ones, and clear the field at your own pace.&lt;/p&gt;

&lt;p&gt;For the handful of legacy offenders you can't fix today, keep an explicit allowlist. And treat adding to that allowlist as the thing you're not allowed to do.&lt;/p&gt;

&lt;p&gt;The list only ever shrinks.&lt;/p&gt;

&lt;p&gt;That's how a gate stays strict without crying wolf — and how you tame inherited code without it blowing up in your face.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gotchas
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A linter only sees what's static.&lt;/strong&gt; Dynamic imports, string-built code, and values resolved at runtime are invisible to it. Know the blind spots. A green lint is not "provably correct."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--fix&lt;/code&gt; is not free thinking.&lt;/strong&gt; Auto-fix is great for unused imports and formatting. It is not great at deciding whether a flagged thing was a real mistake. Read the diff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gate on the trend, not the absolute count.&lt;/strong&gt; Failing CI because the repo has &lt;em&gt;any&lt;/em&gt; warnings is untenable in a vibe-coded codebase. Fail when the count grows past the baseline. That's actionable. "Be perfect" isn't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A rule you suppress everywhere is a rule you deleted.&lt;/strong&gt; If every other line has a disable comment, you didn't pass the gate — you removed it. Fix the code or kill the rule honestly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The mild jab
&lt;/h2&gt;

&lt;p&gt;Here's the irony I can already see coming. You've read this whole piece on why bolting AI onto already-solved problems is wasteful — and your very next move is to open a chat window and type &lt;em&gt;"add ESLint and all the plugins to my repo."&lt;/em&gt; Or worse: &lt;em&gt;"build me a code-review agent that flags unused imports and circular deps."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Stop.&lt;/p&gt;

&lt;p&gt;Both are the wrong move. The first one drops you into a rabbit hole of 1000+ errors you'll be digging out of forever. Start with the base recommendation, then slowly work toward the rest.&lt;/p&gt;

&lt;p&gt;As for the code-review agent — I'll pretend I didn't hear that. We just spent this whole article on why a linter beats an AI reviewer here. So why are you still reaching for it? Look, if you hate your tokens that much — if you're really itching to spend them on a problem a free, decades-old tool already solves &lt;em&gt;deterministically&lt;/em&gt; — just send them my way. I'll put them to better use.&lt;/p&gt;

&lt;p&gt;AI is genuinely good at the fuzzy stuff — turning an idea into reality, that dopamine hit of making something from nothing. Let it do that. Leave the heavy judgement of code quality to linter.&lt;/p&gt;

&lt;p&gt;And let me be honest about the other side: a linter won't fix your architecture, won't catch a wrong business rule, won't tell you the feature was a bad idea. That part is still on you. What it &lt;em&gt;will&lt;/em&gt; do is take the boring, mechanical, never-ending category of mistakes off your plate — so your brain is free for the part that actually needs one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;A linter is the cheapest reviewer on your team. Free, deterministic, tireless, and completely unimpressed by hype.&lt;/p&gt;

&lt;p&gt;Make it a hard gate on merge, and you raise the floor for everyone at once.&lt;/p&gt;

&lt;p&gt;Then teach it your own recurring mistakes — token drift, hardcoded strings, circular deps, unsafe HTML, dropped awaits — one custom rule per bug class, warn-first then ratcheted to error.&lt;/p&gt;

&lt;p&gt;Add the linter first.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Then&lt;/em&gt;, if you still want an agent, at least it's reviewing code that already cleared the bar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The cheapest reviewer you'll ever hire has been sitting in your repo the whole time.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Frontend Is Not That Simple</title>
      <dc:creator>Utkarsh Bansal</dc:creator>
      <pubDate>Thu, 21 May 2026 19:15:01 +0000</pubDate>
      <link>https://dev.to/utkarshbansal01/frontend-is-not-that-simple-199n</link>
      <guid>https://dev.to/utkarshbansal01/frontend-is-not-that-simple-199n</guid>
      <description>&lt;p&gt;I guess most of you already have a pretty basic idea of what this post is about — Frontend Engineering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why frontend?&lt;/strong&gt;&lt;br&gt;
“We have AI now. It can create a website in a day. Why do you even care about frontend anymore? Post something about AI blah blah blah…”&lt;/p&gt;

&lt;p&gt;I hear you.&lt;/p&gt;

&lt;p&gt;But the real question is: &lt;strong&gt;Do you actually understand frontend?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every day, I see product managers and designers trying their hands at AI — creating MVPs in a day and celebrating like, “We don’t need engineers anymore. We can do everything ourselves now.”&lt;/p&gt;

&lt;p&gt;And honestly? That part is impressive.&lt;/p&gt;

&lt;p&gt;But then that same code gets handed over to engineers for optimization, scalability, maintainability, performance, accessibility, security, deployment, and production readiness.&lt;/p&gt;

&lt;p&gt;And that’s where my nightmare begins.&lt;/p&gt;

&lt;p&gt;AI generates code based on patterns and existing code available online. It doesn’t magically create great architecture, scalability, performance, accessibility, or production-grade systems out of thin air.&lt;/p&gt;

&lt;p&gt;The bigger problem starts when people continuously edit AI-generated code using more AI prompts without understanding the underlying structure.&lt;/p&gt;

&lt;p&gt;At first, it works.&lt;/p&gt;

&lt;p&gt;Then slowly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;functions start leaking across modules&lt;/li&gt;
&lt;li&gt;components become tightly coupled&lt;/li&gt;
&lt;li&gt;business logic spreads everywhere&lt;/li&gt;
&lt;li&gt;state management becomes unpredictable&lt;/li&gt;
&lt;li&gt;abstractions collapse&lt;/li&gt;
&lt;li&gt;duplication increases&lt;/li&gt;
&lt;li&gt;and eventually the entire codebase turns into spaghetti&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A tangled mess held together by vibes, Stack Overflow answers, and “it works on my machine.”&lt;/p&gt;

&lt;p&gt;Then comes the question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;“Why hasn’t the app that was created in a day scaled and deployed yet?”&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So for the sake of my sanity, let me take you on a small journey into what real frontend engineering actually looks like.&lt;/p&gt;

&lt;p&gt;And do note — this is just the tip of the iceberg. Once you go deeper, it becomes an abyss.&lt;/p&gt;




&lt;h3&gt;
  
  
  Frontend Engineering
&lt;/h3&gt;

&lt;p&gt;As per product teams:&lt;br&gt;
&lt;em&gt;“Someone who creates beautiful websites using the design team’s instructions.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As per textbooks:&lt;br&gt;
&lt;em&gt;“HTML, CSS, and JavaScript.”&lt;/em&gt;&lt;br&gt;
HTML is the skeleton, CSS is the skin, and JavaScript is the brain.&lt;/p&gt;

&lt;p&gt;As per me?&lt;br&gt;
It’s much more than that.&lt;/p&gt;




&lt;p&gt;Frontend Engineering&lt;br&gt;
├── &lt;strong&gt;UI Development&lt;/strong&gt; — What everyone sees&lt;br&gt;
├── &lt;strong&gt;State Management&lt;/strong&gt; — What no one sees until it breaks&lt;br&gt;
├── &lt;strong&gt;Routing&lt;/strong&gt; — Mostly ignored, but critical unless you enjoy navigation nightmares&lt;br&gt;
├── &lt;strong&gt;Design Systems&lt;/strong&gt; — Design tokens keep the UI consistent&lt;br&gt;
├── &lt;strong&gt;API/Data Layer&lt;/strong&gt; — Most production issues start here&lt;br&gt;
├── &lt;strong&gt;Authentication&lt;/strong&gt; — One of the biggest production concerns&lt;br&gt;
├── &lt;strong&gt;Performance&lt;/strong&gt; — In production, every millisecond matters&lt;br&gt;
├── &lt;strong&gt;Accessibility&lt;/strong&gt; — Most developers ignore this until they shouldn’t&lt;br&gt;
├── &lt;strong&gt;SEO&lt;/strong&gt; — Decides whether people even discover your product&lt;br&gt;
├── &lt;strong&gt;Security&lt;/strong&gt; — Skip this and enjoy your legal/security nightmare&lt;br&gt;
├── &lt;strong&gt;Build Tooling&lt;/strong&gt; — A massive game changer if you truly understand it&lt;br&gt;
├── &lt;strong&gt;Testing&lt;/strong&gt; — Protects both your product and your sleep&lt;br&gt;
├── &lt;strong&gt;Monitoring&lt;/strong&gt; — Users will always find bugs in ways you never expected&lt;br&gt;
├── &lt;strong&gt;Analytics&lt;/strong&gt; — So you can actually measure improvements instead of guessing&lt;br&gt;
├── &lt;strong&gt;Deployment&lt;/strong&gt; — Because shipping localhost to customers isn’t a strategy&lt;br&gt;
├── &lt;strong&gt;CI/CD&lt;/strong&gt; — Automating releases so deployments don’t become rituals&lt;br&gt;
├── &lt;strong&gt;Internationalization&lt;/strong&gt; — Your app eventually speaks more than one language&lt;br&gt;
├── &lt;strong&gt;Offline/PWA&lt;/strong&gt; — Because internet connections aren’t always reliable&lt;br&gt;
├── &lt;strong&gt;Realtime Systems&lt;/strong&gt; — Notifications, chats, collaboration, live updates&lt;br&gt;
├── &lt;strong&gt;Architecture&lt;/strong&gt; — The difference between scaling smoothly and suffering later&lt;br&gt;
└── &lt;strong&gt;Developer Experience&lt;/strong&gt; — Better DX = faster teams and fewer headaches&lt;/p&gt;




&lt;p&gt;Now some people will say:&lt;br&gt;
&lt;em&gt;“Come on, this is an over-the-top explanation.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And honestly?&lt;br&gt;
They’re not completely wrong.&lt;/p&gt;

&lt;p&gt;But it’s also true that all of these areas fall under frontend engineering in modern production systems.&lt;/p&gt;

&lt;p&gt;Now the next question is:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Do we really need all of this?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most of the time? Probably not.&lt;/p&gt;

&lt;p&gt;Modern frameworks already provide many things out of the box.&lt;br&gt;
For example, when you create a Vue project today, you already get tools like Vite, package managers like npm/pnpm/yarn, routing setups, build pipelines, and much more.&lt;/p&gt;

&lt;p&gt;But if you want to build something truly great — something scalable, performant, maintainable, and production-ready — eventually you’ll have to understand these layers.&lt;/p&gt;

&lt;p&gt;That’s where frontend engineering actually begins.&lt;/p&gt;




&lt;p&gt;And if you’re wondering what the “abyss” looks like…&lt;/p&gt;

&lt;p&gt;It looks something like this:&lt;/p&gt;

&lt;p&gt;Frontend Engineering&lt;br&gt;
├── Rendering Strategies (CSR, SSR, SSG, ISR, Streaming)&lt;br&gt;
├── Hydration &amp;amp; Partial Hydration&lt;br&gt;
├── Reactivity Systems &amp;amp; Virtual DOM internals&lt;br&gt;
├── Compiler Architecture&lt;br&gt;
├── Browser Rendering Pipeline&lt;br&gt;
├── GPU Acceleration &amp;amp; Paint Optimization&lt;br&gt;
├── Edge Computing&lt;br&gt;
├── Caching Layers&lt;br&gt;
├── WebSockets &amp;amp; CRDTs&lt;br&gt;
├── Distributed State Synchronization&lt;br&gt;
├── Micro Frontends&lt;br&gt;
├── Monorepo Architecture&lt;br&gt;
├── Design Token Pipelines&lt;br&gt;
├── Runtime Performance Profiling&lt;br&gt;
├── Web Security Hardening&lt;br&gt;
├── Memory Leak Debugging&lt;br&gt;
├── Service Workers&lt;br&gt;
├── Rendering at Scale&lt;br&gt;
├── Bundle Optimization&lt;br&gt;
├── Build System Internals&lt;br&gt;
├── Accessibility Compliance&lt;br&gt;
├── Observability Engineering&lt;br&gt;
├── Frontend Infrastructure&lt;br&gt;
├── Server Components&lt;br&gt;
├── WASM Integration&lt;br&gt;
├── Compiler Toolchains&lt;br&gt;
└── Browser Engine Edge Cases&lt;/p&gt;

&lt;p&gt;And somewhere in between all this, you realize:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Frontend engineering was never just about making buttons look pretty.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>Article 3 of 100: The PR Crisis: GIT/GitHub Commits Cheat Sheet — A Developer’s Redemption Arc</title>
      <dc:creator>Utkarsh Bansal</dc:creator>
      <pubDate>Sun, 02 Mar 2025 14:39:22 +0000</pubDate>
      <link>https://dev.to/utkarshbansal01/article-3-of-100-the-pr-crisis-gitgithub-commits-cheat-sheet-a-developers-redemption-arc-2d1b</link>
      <guid>https://dev.to/utkarshbansal01/article-3-of-100-the-pr-crisis-gitgithub-commits-cheat-sheet-a-developers-redemption-arc-2d1b</guid>
      <description>&lt;p&gt;Handling Git mistakes is a crucial skill for any developer. Recently, I found myself in a situation where a simple feature branch turned into a mess—too many commits, merge conflicts, and unclear history. Instead of starting over, I took the time to properly fix it.&lt;/p&gt;

&lt;p&gt;Here’s what helped:&lt;br&gt;
✔️ git reset — Undo unnecessary commits&lt;br&gt;
✔️ git cherry-pick — Apply specific changes cleanly&lt;br&gt;
✔️ git reflog — Recover lost commits&lt;br&gt;
✔️ git stash — Save work without committing&lt;/p&gt;

&lt;p&gt;Learning to manage Git efficiently makes PRs easier to review and keeps repositories clean.&lt;/p&gt;

&lt;p&gt;If you’ve ever struggled with a tangled Git history, this article might help.&lt;/p&gt;

&lt;p&gt;📖 Read more: &lt;a href="https://medium.com/p/19c1f22e29ed" rel="noopener noreferrer"&gt;https://medium.com/p/19c1f22e29ed&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>git</category>
      <category>cheatsheet</category>
      <category>developer</category>
    </item>
    <item>
      <title>Day 3/100: The PR Crisis: GIT/GitHub Commits Cheat Sheet — A Developer’s Redemption Arc Start here: https://medium.com/p/19c1f22e29ed</title>
      <dc:creator>Utkarsh Bansal</dc:creator>
      <pubDate>Sun, 02 Mar 2025 14:35:50 +0000</pubDate>
      <link>https://dev.to/utkarshbansal01/day-3100-the-pr-crisis-gitgithub-commits-cheat-sheet-a-developers-redemption-arc-start-3e4h</link>
      <guid>https://dev.to/utkarshbansal01/day-3100-the-pr-crisis-gitgithub-commits-cheat-sheet-a-developers-redemption-arc-start-3e4h</guid>
      <description></description>
    </item>
    <item>
      <title>Day 2/100: ‘Wait, don’t we already have this function?’ — Publishing Your First NPM Package 📦</title>
      <dc:creator>Utkarsh Bansal</dc:creator>
      <pubDate>Sat, 15 Feb 2025 17:23:41 +0000</pubDate>
      <link>https://dev.to/utkarsh_bansal_1ea593e019/day-2100-wait-dont-we-already-have-this-function-publishing-your-first-npm-package-5dce</link>
      <guid>https://dev.to/utkarsh_bansal_1ea593e019/day-2100-wait-dont-we-already-have-this-function-publishing-your-first-npm-package-5dce</guid>
      <description>&lt;p&gt;Another project, another déjà vu moment.&lt;/p&gt;

&lt;p&gt;I was about to copy-paste a helper function again when it hit me: “Didn’t I just use this in another repo?” Instead of repeating history, I finally did what I should’ve done long ago—packaged it up and published it to NPM.&lt;/p&gt;

&lt;p&gt;Publishing an NPM package is easier than you think, and once you do it, you’ll wonder why you didn’t sooner. No more hunting through old repos, just clean, reusable code.&lt;/p&gt;

&lt;p&gt;🛠️ Ready to publish yours? Start here: &lt;a href="https://link.medium.com/h2mfQqqn0Qb" rel="noopener noreferrer"&gt;https://link.medium.com/h2mfQqqn0Qb&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/@utkarshbansal01/wait-dont-we-already-have-this-function-publishing-your-first-npm-package-37ddb6c02f39" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fda%3Atrue%2Fresize%3Afill%3A88%3A88%2F0%2AbpnV4_er4ixydXf2" alt="Utkarsh Bansal"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/@utkarshbansal01/wait-dont-we-already-have-this-function-publishing-your-first-npm-package-37ddb6c02f39" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;“Wait, don’t we already have this function” — Publishing Your First NPM Package | by Utkarsh Bansal | Feb, 2025 | Medium&lt;/h2&gt;
      &lt;h3&gt;Utkarsh Bansal ・ &lt;time&gt;Feb 15, 2025&lt;/time&gt; ・ 
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fmedium-f709f79cf29704f9f4c2a83f950b2964e95007a3e311b77f686915c71574fef2.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Day 1/100: Exploring Frontend Storage 🖥️</title>
      <dc:creator>Utkarsh Bansal</dc:creator>
      <pubDate>Sat, 15 Feb 2025 17:17:05 +0000</pubDate>
      <link>https://dev.to/utkarsh_bansal_1ea593e019/day-1100-exploring-frontend-storage-2im8</link>
      <guid>https://dev.to/utkarsh_bansal_1ea593e019/day-1100-exploring-frontend-storage-2im8</guid>
      <description>&lt;p&gt;Modern frontend development isn't just about UI—it’s about efficient data management. From cookies to IndexedDB, each storage option plays a crucial role in performance, security, and user experience.&lt;/p&gt;

&lt;p&gt;​This is my first article where I break down key data management, performance optimization, and security best practices — while addressing key security issues and sharing industry insights… ​ &lt;/p&gt;

&lt;p&gt;​📖 Read: &lt;a href="https://lnkd.in/g-A6H87H" rel="noopener noreferrer"&gt;https://lnkd.in/g-A6H87H&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/@utkarshbansal01/harnessing-frontend-storage-a-comprehensive-guide-to-browser-based-data-management-eaa7cf29d69f" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fda%3Atrue%2Fresize%3Afill%3A88%3A88%2F0%2AbpnV4_er4ixydXf2" alt="Utkarsh Bansal"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/@utkarshbansal01/harnessing-frontend-storage-a-comprehensive-guide-to-browser-based-data-management-eaa7cf29d69f" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Harnessing Frontend Storage: A Comprehensive Guide to Browser-Based Data Management | by Utkarsh Bansal | Feb, 2025 | Medium&lt;/h2&gt;
      &lt;h3&gt;Utkarsh Bansal ・ &lt;time&gt;Feb 14, 2025&lt;/time&gt; ・ 
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fmedium-f709f79cf29704f9f4c2a83f950b2964e95007a3e311b77f686915c71574fef2.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
