How ESLint Made Our Codebase Breathe Again
Every engineer has had that moment: opening a file and being greeted by chaos. Lines of imports scattered in no particular order. Some duplicated, others grouped inconsistently — almost like a visual reminder of how many hands had touched the file over time.
That’s how it felt every time I opened a file in our frontend repositories. It worked, the code always ran. But it didn’t feel right; it was messy, inconsistent, and every new import added to the tangle.
And that’s where this story begins — not with a broken feature or a failing test, but with a quiet frustration and a small, simple goal:
Leave the codebase cleaner than I found it.
The Chaos of Imports
In the wild, our imports looked something like this:
import { Link } from 'react-router-dom';
import Toaster from '../Toaster';
import PropTypes from 'prop-types';
import React, { useState, useRef, useEffect, useCallback } from 'react';
import classNames from 'classnames';Nothing technically wrong — but visually? Hard to scan, hard to maintain.
I imagined what it could look like instead:
import React, { useCallback, useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import classNames from 'classnames';
import Toaster from '../Toaster';Same imports, different energy.
It reads naturally — from framework to libraries to internal components. You can almost feel the logic.
The Idea: Automate Boring Stuffs
That small spark led me to ESLint — specifically, its sort-imports and import/order rules.
The goal wasn’t just to enforce order; it was to encode our sense of craftsmanship into the code itself.
- sort-imports ensures the items on each line stay sorted.
Using the configuration:
"sort-imports": [
"error",
{
ignoreCase: true,
ignoreDeclarationSort: true,
ignoreMemberSort: false,
memberSyntaxSortOrder: ["all", "single", "multiple", "none"],
allowSeparatedGroups: false,
},
],import React, { useEffect, useState, useCallback } from 'react';is corrected to
import React, { useCallback, useEffect, useState } from 'react';- import/order organizes entire groups — built-ins, externals, internals — like chapters in a well-structured book.
I configured them to follow this pattern:
[["builtin", "external"], "internal", ["parent", "sibling"]]And because conventions matter, I gave react, react-dom, and PropTypes reserved spots at the top — the familiar trio that should always greet you when you open a React file.
"import/order": [
"error",
{
groups: [["builtin", "external"], "internal", "parent", "sibling"],
pathGroups: [
{
pattern: "react",
group: "external",
position: "before",
},
{
pattern: "react-dom",
group: "external",
position: "before",
},
{
pattern: "prop-types",
group: "external",
position: "before",
},
],
pathGroupsExcludedImportTypes: ["react", "react-dom", "prop-types"],
"newlines-between": "never",
alphabetize: {
order: "asc",
caseInsensitive: true,
},
},
],The result? Code that looks and feels organized:

Every file started to breathe better.
The Fixing Marathon
I ran yarn lint --fix with the same nervous excitement as running tests after a big refactor.
Some files cleaned themselves up perfectly. Others resisted.
After the auto-fix, I was left staring at 225 stubborn files that needed manual care — one by one.
It wasn’t glamorous work, but it was meaningful. Each file I fixed became a little more readable, a little more consistent.
And consistency is contagious.
The Hidden Problem: Duplicate Imports
While working on the imports, I found another recurring issue — duplicate imports. Same package imported twice in the same file. Easy to miss, but messy and unnecessary.
Examples like these kept popping up:
import { useHistory } from 'react-router-dom';
import { useFeatureFlags } from '../../contexts/FeatureFlagContext';
import { Link } from 'react-router-dom';So I added one more rule to our ESLint configuration:
"no-duplicate-imports": "error"Now, ESLint not only helps us keep things tidy — it protects us from repeating the same mistakes.
Final Thoughts
At first glance, sorting imports doesn’t seem revolutionary. But it’s symbolic of something deeper: Care. When developers take time to improve the small things — the things no one notices until they’re wrong — they build a culture of pride and respect for the codebase.
Every lint rule, every refactor, every cleanup is a way of saying:
“I was here — and I left it better than I found it.”