Jacob Paris
← Back to all content

Use Prettier and ESLint in harmony

ESLint is for catching bugs.

Prettier is for formatting code.

Manually formatting your code tricks you into thinking you're improving the codebase while providing zero business value.

When properly configured, ESLint will audit your code for potential bugs. Anything that doesn't match the way Prettier wants to format your code is also flagged as an error, and then triggers Prettier as part of the autofix step.


You'll need to install these four modules.

npm i --save-dev /
eslint /
prettier /
eslint-config-prettier /
eslint-plugin-prettier /
typescript /

Add these scripts to package.json

The lint:changed script will only lint the currently modified files, which is a great way to slowly integrate linting into a messy codebase

"lint": "eslint",
"lint:changed": "eslint $(git diff --name-only --diff-filter=d HEAD ':(exclude)package*.json' | xargs)",
"lint:fix": "eslint --fix"
## Node
Create a `tsconfig.json` and place it in the root of your application
"compilerOptions": {
"target": "es2016",
"lib": ["ESNext"],
"allowJs": true,
"checkJs": true,
"skipLibCheck": true,
"strictNullChecks": false,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"noImplicitAny": false,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"isolatedModules": true,
"jsx": "preserve",
"baseUrl": "./",
"paths": {
"@/*": ["./*"],
"~/*": ["./*"]
// When adding new paths, run this command to make sure it matches the right files
// npx glob-test "pages/**/**/*.{js,ts,jsx,tsx}"
"include": ["**.d.ts", ".eslintrc.js", "./**/**/*.js"],
"exclude": ["node_modules"]

Create a .eslintrc.js file and place it at the root of your application

module.exports = {
env: {
node: true,
jest: true,
extends: [
/** Automatically replaces "" with `` when ${var} is detected inside */
parser: "@typescript-eslint/parser",
parserOptions: {
project: "./tsconfig.json",
plugins: ["@typescript-eslint", "jest", "prettier"],
ignorePatterns: ["package-lock.json"],
rules: {
// Floating promises are usually a sign of forgetting to await
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-var-requires": "off",
// MongoDB uses _id for its document ID
"no-underscore-dangle": ["error", { allow: ["_id"] }],
Professional headshot

Hey there! I'm a developer, designer, and digital nomad building cool things with Remix, and I'm also writing Moulton, the Remix Community Newsletter

About once per month, I send an email with:

  • New guides and tutorials
  • Upcoming talks, meetups, and events
  • Cool new libraries and packages
  • What's new in the latest versions of Remix

Stay up to date with everything in the Remix community by entering your email below.

Unsubscribe at any time.