Setting up ESLint, Prettier, Husky, and lint-staged in Expo SDK 53+ with Flat Config

July 2025

Maintaining consistent code quality in any project is essential, especially when working in a team. Setting up ESLint, Prettier, Husky, and lint-staged can help you catch issues early, enforce coding standards, and format your code automatically before every commit.

Starting with Expo SDK 53, Expo now uses ESLint’s new Flat Config format as the default configuration approach.

In this guide, I will walk through how to set up these tools in an Expo SDK 53 project using the modern Flat ESLint Config, which is the recommended approach going forward.

As a bonus we will also integrate a prettier plugin to sort import declarations by provided Regular Expression order.

Why this setup?

  • Flat Config (ESLint) — modern, faster, and more flexible ESLint configuration
  • Prettier — automatic and consistent code formatting
  • Import sort & cleanup — organize imports and remove unused ones
  • Husky + lint-staged — automatically lint and format only staged files before each commit

Step 1: Install Dependencies

yarn add -D eslint \
  eslint-config-expo \
  eslint-plugin-unused-imports \
  eslint-plugin-prettier \
  prettier \
  @typescript-eslint/parser \
  @typescript-eslint/eslint-plugin \
  @trivago/prettier-plugin-sort-imports \
  husky \
  lint-staged

Step 2: Set Up ESLint with Flat Config

Create a file named eslint.config.js in the root of your project. This will contain your ESLint configuration using the Flat Config format:

// eslint.config.js
const { defineConfig } = require("eslint/config");
const expoConfig = require("eslint-config-expo/flat");
 
const prettierPlugin = require("eslint-plugin-prettier");
const unusedImportsPlugin = require("eslint-plugin-unused-imports");
 
module.exports = defineConfig([
  expoConfig,
  {
    files: ["**/*.{js,jsx,ts,tsx}"],
    ignores: ["node_modules", "dist", ".expo", "eslint.config.js"],
 
    languageOptions: {
      parser: require("@typescript-eslint/parser"),
      parserOptions: {
        ecmaVersion: "latest",
        sourceType: "module",
        ecmaFeatures: { jsx: true },
        project: "./tsconfig.json",
      },
    },
 
    plugins: {
      prettier: prettierPlugin,
      "unused-imports": unusedImportsPlugin,
    },
 
    rules: {
      // Enable Prettier as an ESLint rule
      "prettier/prettier": [
        "error",
        {
          semi: true,
          singleQuote: false,
          trailingComma: "all",
          printWidth: 100,
        },
      ],
 
      // Remove unused imports and variables
      "@typescript-eslint/no-unused-vars": "off",
      "unused-imports/no-unused-imports": "error",
      "unused-imports/no-unused-vars": [
        "error",
        {
          vars: "all",
          varsIgnorePattern: "^_",
          args: "after-used",
          argsIgnorePattern: "^_",
        },
      ],
      "no-unused-vars": "off",
    },
  },
]);

Step 3: Prettier Configuration

Create a .prettierrc file in the root of your project to configure Prettier:

Paste the below code to your .prettierrc file.

//.prettierrc
{
  "singleQuote": false,
  "semi": true,
  "printWidth": 100,
  "trailingComma": "all",
  "importOrder": ["^react", "^react-native", "<THIRD_PARTY_MODULES>", "^[./]"], // we can add more rules here eg:  "^@components/(.*)$",
  "importOrderSeparation": true,
  "importOrderSortSpecifiers": true,
  "plugins": ["@trivago/prettier-plugin-sort-imports"]
}

The @trivago/prettier-plugin-sort-imports plugin automatically organizes imports based on the regex order defined above.

Install Prettier - Code formatter extension for VS Code.

Step 4: Set Up Husky + lint-staged

1. Add Husky install script

In package.json:

"scripts": {
  "prepare": "husky"
}

Run this to initialize Husky:

yarn prepare

2. Add a pre-commit hook

Create .husky/pre-commit:

echo -e '#!/bin/sh\nyarn lint-staged' > .husky/pre-commit
chmod +x .husky/pre-commit

Note: Do not include . "$(dirname "$0")/_/husky.sh" — it's deprecated and will break in Husky v10.

3. Add lint-staged config to package.json

"lint-staged": {
  "*.{js,jsx,ts,tsx}": [
    "eslint --fix",
    "prettier --write"
  ],
  "*.{json,md,yml}": "prettier --write"
}

Step 5: VS Code Integration

To enable ESLint and Prettier inside VS Code, create (or update) the .vscode/settings.json file in your project root:

{
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll": "always",
    "source.fixAll.eslint": "always"
  },
  "eslint.experimental.useFlatConfig": true,
  "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
  "[json]": {
    "editor.defaultFormatter": "vscode.json-language-features"
  },
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
}

This ensures ESLint and Prettier are applied automatically on save.

Step 6: Testing the implementation

Make a change in your code, then try committing:

git add .
git commit -m "test: husky lint-staged"

You should see Prettier and ESLint run automatically. The commit will fail if lint errors remain.

Demo Repository

Check out a complete working setup here: https://github.com/souravbaranwal/eslint-demo-app

This repo contains all the configs discussed above, fully integrated with an Expo SDK 53+ app.

Conclusion

With this setup in place:

  • Your codebase stays clean and consistent
  • Imports are automatically sorted and unused ones removed
  • You are future-proofed with ESLint’s modern Flat Config

Now your Expo app is fully linted, formatted, and Git-commit ready, with zero manual intervention.

Happy coding!