Code Quality Automation: ESLint Rules, Prettier, and Custom Linting
Artem Turlenko

Artem Turlenko @artem_turlenko

About: Full-Stack Software Developer | UI/UX Designer

Location:
Essen, North Rhine-Westphalia, Germany
Joined:
Feb 11, 2025

Code Quality Automation: ESLint Rules, Prettier, and Custom Linting

Publish Date: Jun 25
2 0

As a Frontend-Backend Engineer, I've seen projects struggle with code consistency and quality. Manual code reviews can't catch everything, and style discussions waste precious development time. The solution? Robust code quality automation that works seamlessly in your workflow.

The Modern Code Quality Stack

The holy trinity of automated code quality consists of:

  • ESLint: Error detection and code quality rules
  • Prettier: Consistent code formatting
  • Custom Rules: Domain-specific requirements

Let's dive into setting up a production-ready system.

Advanced ESLint Configuration

Skip the basic .eslintrc.js approach. Modern projects need modular, environment-aware configurations:

// eslint.config.js (ESLint 9+ flat config)
import js from '@eslint/js';
import typescript from '@typescript-eslint/eslint-plugin';
import react from 'eslint-plugin-react';
import security from 'eslint-plugin-security';

export default [
  js.configs.recommended,

  // TypeScript files
  {
    files: ['**/*.{ts,tsx}'],
    languageOptions: {
      parser: '@typescript-eslint/parser',
      parserOptions: {
        project: './tsconfig.json',
      },
    },
    plugins: { '@typescript-eslint': typescript },
    rules: {
      '@typescript-eslint/no-unused-vars': 'error',
      '@typescript-eslint/explicit-function-return-type': 'warn',
      '@typescript-eslint/prefer-nullish-coalescing': 'error',
    },
  },

  // React components - accessibility focus
  {
    files: ['src/components/**/*.{jsx,tsx}'],
    plugins: { react },
    rules: {
      'react/prop-types': 'off',
      'react-hooks/exhaustive-deps': 'error',
      'jsx-a11y/alt-text': 'error',
    },
  },

  // API routes - security focus
  {
    files: ['src/api/**/*.{js,ts}'],
    plugins: { security },
    rules: {
      'security/detect-object-injection': 'error',
      'no-console': 'error',
    },
  },
];
Enter fullscreen mode Exit fullscreen mode

Prettier Integration Without Conflicts

The secret to ESLint-Prettier harmony is proper configuration:

// .prettierrc.js
module.exports = {
  semi: true,
  singleQuote: true,
  trailingComma: 'es5',
  printWidth: 80,

  overrides: [
    {
      files: '*.{ts,tsx}',
      options: {
        trailingComma: 'all',
      },
    },
  ],
};
Enter fullscreen mode Exit fullscreen mode
// In your ESLint config
{
  plugins: { prettier: require('eslint-plugin-prettier') },
  extends: ['prettier'], // Disables conflicting rules
  rules: {
    'prettier/prettier': 'error',
  },
}
Enter fullscreen mode Exit fullscreen mode

Building Custom ESLint Rules

Sometimes you need domain-specific rules. Here's a custom rule that enforces consistent error handling:

// rules/consistent-error-handling.js
module.exports = {
  meta: {
    type: 'problem',
    fixable: 'code',
    messages: {
      inconsistentError: 'Error "{{ errorName }}" should start with "error" or "err"',
    },
  },

  create(context) {
    return {
      CatchClause(node) {
        const param = node.param;

        if (param && param.type === 'Identifier') {
          const errorName = param.name;
          const validPatterns = ['error', 'err', 'e'];

          if (!validPatterns.some(pattern => 
            errorName.toLowerCase().startsWith(pattern))) {
            context.report({
              node: param,
              messageId: 'inconsistentError',
              data: { errorName },
              fix(fixer) {
                return fixer.replaceText(param, 'error');
              },
            });
          }
        }
      },
    };
  },
};
Enter fullscreen mode Exit fullscreen mode

CI/CD Integration That Actually Works

Automate quality checks in your pipeline:

# .github/workflows/code-quality.yml
name: Code Quality

on: [push, pull_request]

jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '18'
          cache: 'npm'

      - run: npm ci

      - name: ESLint with SARIF
        run: |
          npx eslint . \
            --format=@microsoft/eslint-formatter-sarif \
            --output-file=eslint-results.sarif \
            --max-warnings=0

      - name: Upload to GitHub Security
        uses: github/codeql-action/upload-sarif@v2
        if: always()
        with:
          sarif_file: eslint-results.sarif

      - name: Prettier Check
        run: npx prettier --check .
Enter fullscreen mode Exit fullscreen mode

Pre-commit Hooks for Instant Feedback

// package.json
{
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix --max-warnings=0",
      "prettier --write"
    ],
    "*.{json,md,yml}": ["prettier --write"]
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Performance Optimization Tips

Large codebases need optimized linting:

// Fast rules (prefer these)
'prefer-const': 'error',
'no-var': 'error',
'eqeqeq': 'error',

// Expensive rules (use sparingly)
'@typescript-eslint/no-floating-promises': 'warn', // Requires type checking
'import/no-cycles': 'warn', // Can be very slow

// Use ignores for better performance
ignores: [
  'node_modules/**',
  'dist/**',
  '*.min.js',
  '**/*.d.ts', // Skip unless necessary
],
Enter fullscreen mode Exit fullscreen mode

Gradual Adoption Strategy

Introduce new rules progressively:

const LINT_PHASE = process.env.LINT_PHASE || 'introduction';

const ruleLevel = {
  introduction: 'warn',  // Week 1-2: Show warnings
  enforcement: 'error',  // Week 3-4: Block new violations
  strict: 'error',       // Week 5+: Fix all violations
}[LINT_PHASE];

export default [{
  rules: {
    'prefer-const': ruleLevel,
    'complexity': [ruleLevel, { max: 15 }],
  },
}];
Enter fullscreen mode Exit fullscreen mode

The Bottom Line

Effective code quality automation isn't about having the most rules—it's about having the right rules that:

  1. Catch real problems before they reach production
  2. Enforce team standards without slowing development
  3. Scale with your codebase and team size
  4. Integrate seamlessly into your workflow

Start with a solid ESLint + Prettier foundation, add context-aware rules for different parts of your application, and gradually introduce custom rules for your specific domain needs.

Your future self (and your teammates) will thank you when code reviews focus on logic and architecture instead of style discussions.


What's your biggest code quality challenge? Share your experience in the comments below! 👇

Comments 0 total

    Add comment