DEV Community

Cover image for How to Create an ESLint Config Package in Turborepo
Saiful Islam
Saiful Islam

Posted on

2

How to Create an ESLint Config Package in Turborepo

In a growing monorepo, maintaining consistent code quality across multiple apps and packages is crucial. One powerful way to do this is by creating a shared ESLint config package. In this post, Iโ€™ll walk you through how I set up a reusable ESLint config inside a Turborepo-based monorepo โ€” perfect for full-stack projects using TypeScript, React, and Node.js.

โœ… Related: How to Create a TypeScript Config Package in Turborepo


๐Ÿงฉ Step-by-Step: Creating the @dtr-cli/eslint-config Package

1. Create a Package Folder

Inside your packages folder, create a new directory for the ESLint config package:

mkdir -p packages/eslint-config
cd packages/eslint-config
npm init -y
Enter fullscreen mode Exit fullscreen mode

2. Update the package.json with a proper name and export map:

{
  "name": "@dtr-cli/eslint-config",
  "version": "0.0.1",
  "description": "Shared Eslint configuration for @dtr-cli",
  "license": "ISC",
  "author": "Saiful Islam <saiful.islam.rafi.88@gmail.com>",
  "exports": {
    "./base-eslint-config": "./base-eslint-config.js",
    "./backend-eslint-config": "./backend-eslint-config.js",
    "./react-eslint-config": "./react-eslint-config.js",
    "./frontend-eslint-config": "./frontend-eslint-config.js",
    "./extension-eslint-config": "./extension-eslint-config.js",
    "./ui-eslint-config": "./ui-eslint-config.js"
  },
  "files": [
    "base-eslint-config.js",
    "backend-eslint-config.js",
    "react-eslint-config.js",
    "frontend-eslint-config.js",
    "extension-eslint-config.js",
    "ui-eslint-config.js"
  ],
  "devDependencies": {
    "@eslint/js": "^9.26.0",
    "@tanstack/eslint-plugin-query": "^5.74.7",
    "eslint-config-prettier": "^10.1.3",
    "eslint-plugin-react": "^7.37.5",
    "eslint-plugin-react-hooks": "^5.2.0",
    "eslint-plugin-react-refresh": "^0.4.20",
    "eslint-plugin-turbo": "^2.5.3",
    "globals": "^16.1.0",
    "typescript-eslint": "^8.32.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Create Base ESLint Config

base-eslint-config.js

This config includes basic settings for TypeScript, TurboRepo, and Prettier:

import eslintJs from "@eslint/js";
import eslintConfigPrettier from "eslint-config-prettier";
import turboPlugin from "eslint-plugin-turbo";
import tseslint from "typescript-eslint";

export const baseEslintConfig = [
  eslintConfigPrettier,
  eslintJs.configs.recommended,
  turboPlugin.configs["flat/recommended"],
  ...tseslint.configs.recommended,
  {
    languageOptions: {
      ecmaVersion: 2020,
    },
    rules: {
      "turbo/no-undeclared-env-vars": "warn",
    },
  },
];
Enter fullscreen mode Exit fullscreen mode

4. Create targeted ESLint config

๐Ÿ”ง backend-eslint-config.js
import globals from "globals";
import { baseEslintConfig } from "./base-eslint-config";

export const backendEslintConfig = [
  ...baseEslintConfig,
  {
    languageOptions: {
      globals: globals.node,
    },
  },
];
Enter fullscreen mode Exit fullscreen mode
โš›๏ธ react-eslint-config.js
import reactEslint from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import globals from "globals";
import { baseEslintConfig } from "./base-eslint-config";

export const reactEslintConfig = [
  ...baseEslintConfig,
  reactEslint.configs.flat.recommended,
  reactHooks.configs["recommended-latest"],
  reactRefresh.configs.recommended,
  {
    settings: {
      react: { version: "19.1.0" },
    },
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
    },
    rules: {
      "react/react-in-jsx-scope": "off",
      "react/prop-types": "off",
      "react-refresh/only-export-components": [
        "warn",
        { allowConstantExport: true },
      ],
    },
  },
];
Enter fullscreen mode Exit fullscreen mode
๐Ÿงฉ frontend-eslint-config.js
import { reactEslintConfig } from "./react-eslint-config";

export const frontendEslintConfig = [...reactEslintConfig];
Enter fullscreen mode Exit fullscreen mode
๐Ÿงช extension-eslint-config.js
import { reactEslintConfig } from "./react-eslint-config.js";
import pluginQuery from "@tanstack/eslint-plugin-query";

export const extensionEslintConfig = [
  ...reactEslintConfig,
  ...pluginQuery.configs["flat/recommended"],
];
Enter fullscreen mode Exit fullscreen mode
๐ŸŽจ ui-eslint-config.js
import { reactEslintConfig } from "./react-eslint-config.js";

export const uiEslintConfig = [...reactEslintConfig];
Enter fullscreen mode Exit fullscreen mode

Use the ESLint Config Package

In any project inside your monorepo, like apps/backend, create an eslint.config.mjs:

import { backendEslintConfig } from "@dtr-cli/eslint-config/backend-eslint-config";

/** @type {import("eslint").Linter.Config} */
export default [
  ...backendEslintConfig,
  {
    ignores: ["dist/**"],
  },
];
Enter fullscreen mode Exit fullscreen mode

apps/frontend create an eslint-config.js

import { frontendEslintConfig } from "@dtr-cli/eslint-config/frontend-eslint-config";

/** @type {import("eslint").Linter.Config} */
export default [...frontendEslintConfig];
Enter fullscreen mode Exit fullscreen mode

Final Thoughts

Having a centralized ESLint config package in your Turborepo setup is a massive productivity and consistency boost. Instead of rewriting and maintaining config files in every app, you can rely on one source of truth that scales with your repo.

This setup supports various contexts like backend, React apps, extensions, and UI libraries โ€” making your developer experience smoother and your codebase cleaner.

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

Top comments (0)

AWS GenAI LIVE image

How is generative AI increasing efficiency?

Join AWS GenAI LIVE! to find out how gen AI is reshaping productivity, streamlining processes, and driving innovation.

Learn more