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!