Shared Configs
Shared ESLint and TypeScript configurations used across all workspaces.
Two config packages keep ESLint and TypeScript settings consistent across the monorepo. Every workspace extends one of their presets.
Directory Structure
Which Config Goes Where
| Workspace | ESLint | TypeScript |
|---|---|---|
apps/native | next.js | nextjs.json |
apps/web | next.js | nextjs.json |
packages/ui | react-internal.js | react-library.json |
packages/core | react-internal.js | react-library.json |
packages/i18n | base.js | base.json |
packages/cli | base.js | base.json |
ESLint Config (@workspace/eslint-config)
ESLint 9 flat config format. Three presets, each building on the previous:
import js from "@eslint/js";
import eslintConfigPrettier from "eslint-config-prettier";
import onlyWarn from "eslint-plugin-only-warn";
import turboPlugin from "eslint-plugin-turbo";
import tseslint from "typescript-eslint";
export const config = [
js.configs.recommended,
eslintConfigPrettier,
...tseslint.configs.recommended,
{
plugins: { turbo: turboPlugin },
rules: { "turbo/no-undeclared-env-vars": "warn" },
},
{ plugins: { onlyWarn } },
{ ignores: ["dist/**", ".next/**"] },
];| Plugin | What it does |
|---|---|
@eslint/js | ESLint recommended ruleset |
typescript-eslint | TypeScript-aware rules |
eslint-config-prettier | Disables rules that conflict with Prettier |
eslint-plugin-turbo | Validates Turborepo env var declarations |
eslint-plugin-only-warn | Downgrades all errors to warnings |
import js from "@eslint/js"
import pluginNext from "@next/eslint-plugin-next"
import eslintConfigPrettier from "eslint-config-prettier"
import pluginReact from "eslint-plugin-react"
import pluginReactHooks from "eslint-plugin-react-hooks"
import globals from "globals"
import tseslint from "typescript-eslint"
import { config as baseConfig } from "./base.js"
export const nextJsConfig = [
...baseConfig,
js.configs.recommended,
eslintConfigPrettier,
...tseslint.configs.recommended,
{
...pluginReact.configs.flat.recommended,
languageOptions: {
...pluginReact.configs.flat.recommended.languageOptions,
globals: { ...globals.serviceworker },
},
},
{
plugins: { "@next/next": pluginNext },
rules: {
...pluginNext.configs.recommended.rules,
...pluginNext.configs["core-web-vitals"].rules,
},
},
{
plugins: { "react-hooks": pluginReactHooks },
settings: { react: { version: "detect" } },
rules: {
...pluginReactHooks.configs.recommended.rules,
"react/react-in-jsx-scope": "off",
"react/prop-types": "off",
},
},
]Extends base.js with Next.js plugin (recommended + core-web-vitals rules), React, React Hooks, and service worker globals.
Same as next.js with two differences:
- No
@next/eslint-plugin-next— this isn't a Next.js app - Adds
globals.browser— sincepackages/uicomponents run directly in the browser
Used by packages/ui.
ESLint Usage
Each workspace imports the appropriate preset:
import { nextJsConfig } from "@workspace/eslint-config/next";
export default [...nextJsConfig];import { config } from "@workspace/eslint-config/react-internal";
export default [...config];TypeScript Config (@workspace/typescript-config)
Three configs that extend each other:
{
"$schema": "https://json.schemastore.org/tsconfig",
"display": "Default",
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"esModuleInterop": true,
"incremental": false,
"isolatedModules": true,
"lib": ["es2022", "DOM", "DOM.Iterable"],
"module": "NodeNext",
"moduleDetection": "force",
"moduleResolution": "NodeNext",
"noUncheckedIndexedAccess": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"target": "ES2022"
}
}strict: true + noUncheckedIndexedAccess enforces strict type checking. incremental: false is set because Turborepo handles caching.
{
"$schema": "https://json.schemastore.org/tsconfig",
"display": "Next.js",
"extends": "./base.json",
"compilerOptions": {
"plugins": [{ "name": "next" }],
"module": "ESNext",
"moduleResolution": "Bundler",
"allowJs": true,
"jsx": "preserve",
"noEmit": true
}
}Overrides module resolution to Bundler (Next.js uses its own bundler), enables the Next.js TypeScript plugin for route type checking, and sets noEmit since Next.js handles compilation.
{
"$schema": "https://json.schemastore.org/tsconfig",
"display": "React Library",
"extends": "./base.json",
"compilerOptions": {
"jsx": "react-jsx"
}
}react-jsx transform means no import React needed in component files.
TypeScript Usage
{
"extends": "@workspace/typescript-config/nextjs.json"
}Adding a new package? Extend react-internal.js + react-library.json for React packages, or base.js + base.json for plain TypeScript utilities.