Alternar tema

Configuração profissional no Next.js: ESLint + Prettier + Husky do zero

Easton editorial illustration: route-map drafting table

O pesadelo de uma sexta-feira à noite

Lembro bem da sexta-feira passada. Eu já estava prestes a desligar o computador e ir para casa quando vi uma mensagem do líder técnico no Slack: “Seu PR tem muitos problemas de formatação. Você pode arrumar isso antes de enviar novamente?” Abri o GitHub e encontrei uma tela cheia de diffs em vermelho, tudo porque alguns trechos usavam aspas duplas e outros tinham recuos inconsistentes.

Para ser sincero, bateu uma sensação enorme de impotência. Eu tinha quase certeza de que havia executado npm run lint antes do commit. Então por que ainda havia problemas? Para piorar, outro colega passou pela mesma situação. A lógica do código dele estava perfeita, mas a formatação era diferente da minha, e o merge acabou gerando vários conflitos sem qualquer valor.

Você já passou por isso? O código funciona bem, mas problemas de formatação fazem o PR ir e voltar na revisão, desperdiçando o tempo de todo mundo. Naquele momento, pensei: não existe uma solução definitiva que deixe a máquina cuidar automaticamente dessas tarefas repetitivas?

Existe: a combinação ESLint + Prettier + Husky.

Por que precisamos dessas três ferramentas?

Confesso que, quando ouvi esses três nomes pela primeira vez, também achei que parecia complicado demais. Depois de algum tempo usando as ferramentas, porém, não quis mais voltar atrás. Veja o valor de cada uma.

ESLint: o guardião da qualidade do código

Muita gente pensa que o ESLint serve apenas para verificar a formatação. Na verdade, sua função mais importante é detectar possíveis problemas no código.

Por exemplo, o Next.js recomenda o componente <Image> no lugar da tag HTML <img>, pois o primeiro oferece otimização automática. Se você escrever <img> sem perceber, o ESLint exibirá imediatamente um erro como este:

Error: Do not use <img>. Use Image from 'next/image' instead.

Esse tipo de aviso evita armadilhas de desempenho ainda durante o desenvolvimento. É muito mais eficiente do que descobrir, depois do lançamento, que as imagens carregam devagar e só então tentar otimizá-las.

O Next.js 15 habilita o ESLint por padrão, mas é preciso configurá-lo corretamente para aproveitar todo o seu potencial.

Prettier: a solução definitiva para formatação

O ESLint se concentra na lógica e na qualidade do código, enquanto o Prettier cuida da formatação. Cada ferramenta tem uma função clara, e não devemos misturá-las.

Antes, nosso time discutia com frequência por causa da formatação: algumas pessoas preferiam aspas simples, outras aspas duplas; algumas usavam recuo de 2 espaços, outras de 4. Cada code review acabava desviando para esses detalhes pouco importantes, o que era uma grande perda de tempo.

Depois de configurar o Prettier, esses problemas desapareceram. Basta definir as regras com o time no início do projeto — por exemplo, usar sempre aspas simples e recuo de 2 espaços — e o Prettier passa a formatar todo o código automaticamente. Configure uma vez e aproveite por muito tempo.

Husky: a peça-chave da automação

Por melhor que uma ferramenta seja, se depender de execução manual, alguém acabará esquecendo.

Isso já aconteceu comigo várias vezes: durante o desenvolvimento local, esqueci de executar npm run lint e fiz o commit diretamente. O pipeline de CI falhou e bloqueou o deploy de todo o time. É o tipo de constrangimento que ninguém quer repetir.

O Husky serve justamente para executar verificações automaticamente antes do commit. Na etapa de pre-commit do Git, ele intercepta o commit e roda ESLint e Prettier primeiro. O commit só é permitido quando o código está de acordo com as regras.

Em conjunto com o lint-staged, o Husky verifica apenas os arquivos modificados, em vez de analisar o projeto inteiro. Por isso, a execução é muito rápida e o hook de pre-commit não atrasa o fluxo de desenvolvimento.

A força das três ferramentas juntas

Com as três ferramentas combinadas, o fluxo funciona assim:

  1. O ESLint define regras de qualidade do código, como proibir var e exigir const ou let
  2. O Prettier padroniza a formatação, como usar aspas simples em todas as strings
  3. O Husky executa as verificações automaticamente antes do commit, evitando esquecimentos

Os benefícios para o time são claros:

  • O PR review deixa de perder tempo com formatação e se concentra na lógica de negócio
  • Os conflitos de merge diminuem, pois a formatação é uniforme
  • A taxa de falhas na CI cai, já que o código é verificado antes do commit

Processo completo de configuração

Agora vamos à prática. Vou orientar você passo a passo na configuração dessa cadeia de ferramentas, evitando os problemas mais comuns.

Etapa 1: inicialize um projeto Next.js

Se você já tem um projeto, pode pular esta etapa. Para um projeto novo, execute:

npx create-next-app@latest my-app
cd my-app

Durante a criação, selecione TypeScript e ESLint. O Next.js 15 habilita o ESLint por padrão, o que já economiza algum trabalho.

Etapa 2: instale as dependências

Execute o comando abaixo. Eu uso pnpm, mas você também pode usar npm ou yarn:

pnpm add -D eslint eslint-config-next prettier eslint-config-prettier husky lint-staged

Veja rapidamente a função de cada pacote:

  • eslint: núcleo do ESLint
  • eslint-config-next: configuração oficial do ESLint para Next.js, incluindo regras específicas do framework
  • prettier: núcleo do Prettier
  • eslint-config-prettier: desativa regras de formatação do ESLint que entram em conflito com o Prettier
  • husky: gerenciador de Git hooks
  • lint-staged: executa verificações apenas nos arquivos em staging

Atenção: não instale eslint-plugin-prettier. Muitos tutoriais recomendam esse pacote, mas ele executa o Prettier como uma regra do ESLint e pode causar problemas de desempenho. A abordagem correta é executar ESLint e Prettier separadamente.

Etapa 3: configure o ESLint

Esta é a etapa em que mais surgem problemas, principalmente porque a migração do Next.js 15 para o ESLint 9 mudou o formato de configuração.

Use o formato Flat Config do ESLint 9 (recomendado)

Crie o arquivo eslint.config.mjs na raiz do projeto:

// eslint.config.mjs
import { FlatCompat } from '@eslint/eslintrc';
import nextPlugin from '@next/eslint-plugin-next';

const compat = new FlatCompat();

export default [
  ...compat.extends('next/core-web-vitals'),
  {
    plugins: {
      '@next/next': nextPlugin,
    },
    rules: {
      '@next/next/no-img-element': 'error',
      'react/no-unescaped-entities': 'off',
      // Adicione suas próprias regras aqui
    },
  },
  {
    ignores: ['.next/', 'node_modules/', 'out/'],
  },
];

Pontos importantes:

  • O ESLint 9 não usa mais .eslintrc.json; ele adota o formato flat config em eslint.config.mjs
  • Se, depois de atualizar para o Next.js 15, você encontrar o erro “The Next.js plugin was not detected”, provavelmente o formato da configuração está incorreto
  • O Next.js 16 removerá o comando next lint, então vale a pena se adaptar ao novo formato desde já

Alternativa temporária em caso de incompatibilidade

Se você ainda não quiser lidar com o flat config, pode definir uma variável de ambiente e voltar ao formato de configuração do ESLint 8:

ESLINT_USE_FLAT_CONFIG=false

Depois, continue usando .eslintrc.json:

{
  "extends": ["next/core-web-vitals", "prettier"],
  "rules": {
    "@next/next/no-img-element": "error"
  }
}

Ainda assim, recomendo migrar para o flat config o quanto antes, pois essa é a direção futura da ferramenta.

Etapa 4: configure o Prettier

Crie .prettierrc.json na raiz do projeto:

{
  "semi": true,
  "singleQuote": true,
  "trailingComma": "es5",
  "tabWidth": 2,
  "printWidth": 80,
  "arrowParens": "avoid"
}

Essas são as configurações que eu prefiro, mas você pode ajustá-las às práticas do seu time:

  • singleQuote: true: prefiro aspas simples, pois acho o código mais limpo
  • printWidth: 80: limita cada linha a 80 caracteres, o que funciona bem ao exibir várias janelas do editor lado a lado
  • trailingComma: 'es5': adiciona vírgula ao último item de objetos e arrays, deixando o Git diff mais limpo

Crie também .prettierignore para informar ao Prettier quais arquivos devem ser ignorados:

.next
out
node_modules
public
*.lock

Integração com o VSCode (opcional, mas recomendada)

Se você usa VSCode, crie .vscode/settings.json para formatar o código automaticamente ao salvar:

{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode"
}

Assim, sempre que você pressionar Ctrl + S para salvar um arquivo, o Prettier formatará o código automaticamente. É muito prático.

Etapa 5: configure Husky + lint-staged

Esta é a parte mais valiosa de todo o processo e a que mais melhora a colaboração no time.

Inicialize o Husky

Execute:

pnpm dlx husky init

Esse comando cria automaticamente a pasta .husky/ e adiciona o script prepare ao package.json:

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

O script prepare garante que os hooks do Husky sejam instalados automaticamente quando os integrantes do time executarem pnpm install. Assim, quem entrar no projeto não precisará de nenhuma etapa extra: basta clonar o repositório e aproveitar as verificações automáticas.

Configure o hook de pre-commit

Edite o arquivo .husky/pre-commit:

pnpm lint-staged

É só isso. Toda vez que você executar git commit, o Husky rodará pnpm lint-staged primeiro.

Configure o lint-staged

Crie .lintstagedrc.mjs na raiz do projeto:

export default {
  '*.{js,jsx,ts,tsx}': [
    'eslint --fix',
    'prettier --write',
  ],
  '*.{json,md,css}': [
    'prettier --write',
  ],
};

Essa configuração faz o seguinte:

  • Para arquivos .js, .jsx, .ts e .tsx, executa primeiro eslint --fix, que corrige problemas automaticamente, e depois prettier --write, que aplica a formatação
  • Para arquivos .json, .md e .css, executa apenas prettier --write

Dicas de otimização de desempenho:

  1. Verifique apenas arquivos em staging: o lint-staged filtra automaticamente os arquivos adicionados com git add, sem analisar o projeto inteiro
  2. Evite verificações globais: nunca execute pnpm lint no pre-commit, pois ele verifica o projeto inteiro e pode ser lento
  3. Pule os testes: use o pre-commit apenas para formatação e verificações básicas de qualidade; deixe os testes mais complexos para a CI
  4. Ignore a verificação em uma emergência: se você realmente precisar pular as verificações, por exemplo para uma correção urgente em produção, use git commit --no-verify

Solução de problemas comuns

O Husky não funciona no Windows

Se você usa Windows, verifique se o Git está configurado para usar o Git Bash, e não o CMD ou PowerShell. Confira também se o arquivo .husky/pre-commit tem permissão de execução:

chmod +x .husky/pre-commit

O hook demora demais para executar

Se o hook de pre-commit levar mais de 10 segundos, confira a configuração do lint-staged e verifique se ela não está analisando o projeto inteiro por engano. Em condições normais, o lint-staged leva de 2 a 3 segundos para verificar apenas alguns arquivos.

Valide a configuração

Depois de concluir a configuração, vamos verificar se tudo funciona.

Etapas do teste

  1. Modifique qualquer arquivo e introduza intencionalmente um problema de formatação, como trocar aspas simples por duplas ou remover alguns pontos e vírgulas
  2. Execute git add .
  3. Execute git commit -m "test"
  4. Observe a saída do terminal

Como reconhecer que deu certo

Se a configuração estiver correta, você verá uma saída parecida com esta:

✔ Preparing lint-staged...
✔ Running tasks for staged files...
✔ Applying modifications from tasks...
✔ Cleaning up temporary files...

Abra o arquivo modificado e você verá que os problemas de formatação foram corrigidos automaticamente. Esse é o poder da automação.

Se algo falhar

  • Confirme se o arquivo .husky/pre-commit existe e se o conteúdo está correto
  • Confirme se .lintstagedrc.mjs está na raiz do projeto
  • Tente executar pnpm lint-staged manualmente e observe se aparece alguma mensagem de erro

Configuração avançada

A configuração básica já atende à maioria das necessidades, mas você pode adotar as opções abaixo se quiser um controle de qualidade mais rigoroso.

Adicione o commitlint para padronizar mensagens de commit

Além da formatação do código, também é importante padronizar as mensagens de commit. O commitlint garante que todo o time siga o mesmo formato, como Conventional Commits.

Instale as dependências:

pnpm add -D @commitlint/cli @commitlint/config-conventional

Crie commitlint.config.mjs:

export default {
  extends: ['@commitlint/config-conventional'],
};

Adicione o hook de commit-msg:

echo "pnpm commitlint --edit \$1" > .husky/commit-msg

Agora, se a mensagem do commit não seguir o padrão, como git commit -m "fix bug" em vez de git commit -m "fix: bug", o commit será bloqueado.

Adicione a verificação de tipos do TypeScript

Se quiser executar automaticamente a verificação de tipos do TypeScript antes do commit, altere .lintstagedrc.mjs:

export default {
  '*.{ts,tsx}': [
    () => 'tsc --noEmit', // Verificação de tipos
    'eslint --fix',
    'prettier --write',
  ],
  '*.{js,jsx}': [
    'eslint --fix',
    'prettier --write',
  ],
  '*.{json,md,css}': [
    'prettier --write',
  ],
};

Atenção: tsc --noEmit verifica os tipos do projeto inteiro e pode ser lento. Se o projeto for grande, isso pode atrasar o hook de pre-commit. Pessoalmente, recomendo deixar a verificação de tipos para a CI e usar o pre-commit apenas para formatação e verificações básicas.

Configuração para Monorepo

Se o seu projeto for um Monorepo, por exemplo com pnpm workspace ou Turborepo, a configuração é um pouco mais complexa:

  • Instale Husky e lint-staged na raiz
  • Crie um .lintstagedrc.mjs independente em cada package
  • Evite que a configuração “vaze” para outros packages

Consulte a documentação oficial do lint-staged para ver os detalhes da configuração.

Problemas comuns e soluções

Alguns problemas podem surgir durante a configuração. Veja abaixo as armadilhas mais frequentes e como resolvê-las.

P1: o que fazer quando as regras do ESLint e do Prettier entram em conflito?

Sintoma: o ESLint informa que a formatação de uma linha está incorreta, mas, depois que o Prettier a formata, ela volta ao estado anterior.

Solução:

Confirme que eslint-config-prettier está instalado e que prettier aparece por último nos extends da configuração do ESLint:

export default [
  ...compat.extends('next/core-web-vitals'),
  ...compat.extends('prettier'), // Deve ficar por último
];

O eslint-config-prettier desativa todas as regras do ESLint que entram em conflito com o Prettier. Assim, o Prettier fica responsável pela formatação e o ESLint pela qualidade do código.

P2: o ESLint exibe o erro “plugin not detected” depois da atualização para o Next.js 15

Sintoma: ao executar pnpm lint, aparece o seguinte erro:

Error: The Next.js plugin was not detected in your ESLint configuration.

Solução:

Isso normalmente acontece porque o formato flat config do ESLint 9 está incorreto. Confira se eslint.config.mjs importa corretamente @next/eslint-plugin-next:

import nextPlugin from '@next/eslint-plugin-next';

export default [
  {
    plugins: {
      '@next/next': nextPlugin,
    },
  },
];

Se ainda não conseguir resolver, defina temporariamente ESLINT_USE_FLAT_CONFIG=false para voltar ao formato antigo.

P3: como acelerar um hook de pre-commit muito lento?

Sintoma: cada commit leva mais de 10 segundos, prejudicando bastante o ritmo de desenvolvimento.

Solução:

  1. Confirme que o lint-staged verifica apenas os arquivos em staging; normalmente, isso é automático
  2. Remova os scripts de teste do pre-commit, pois os testes devem ser executados na etapa de CI
  3. Se o projeto for grande, considere executar o ESLint apenas nos arquivos .ts e .tsx e usar apenas o Prettier nos demais

P4: os integrantes do time não têm os hooks do Husky instalados

Sintoma: depois de clonar o projeto, um novo integrante faz commits sem acionar o hook de pre-commit.

Solução:

Confirme que package.json contém o script prepare:

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

Peça ao colega para executar pnpm install uma vez. Os hooks do Husky serão instalados automaticamente.

P5: o Husky não funciona no Windows

Sintoma: para usuários do Windows, o hook de pre-commit não é executado durante o commit.

Solução:

  1. Confirme que o Git está configurado para usar o Git Bash, e não o CMD
  2. Verifique as permissões do arquivo .husky/pre-commit e tente adicionar manualmente a permissão de execução:
chmod +x .husky/pre-commit
  1. Se ainda não funcionar, reinicialize o Husky:
rm -rf .husky
pnpm dlx husky init

Resumo e boas práticas

Levei cerca de meia hora para configurar essa cadeia de ferramentas, mas o valor que ela trouxe para o time é duradouro.

Principais benefícios

  • Mais qualidade no código: o ESLint encontra possíveis problemas ainda durante o desenvolvimento e ajuda a evitar incidentes em produção
  • Colaboração mais eficiente: a formatação padronizada reduz discussões sem sentido nos PRs e diminui conflitos de merge
  • Garantia por automação: o Husky assegura que cada commit siga as regras, sem depender da memória de cada pessoa

Recomendações de boas práticas

  1. Configure aos poucos: não comece com regras rígidas demais. Use a configuração padrão por algum tempo e faça ajustes gradualmente conforme os problemas aparecerem.
  2. Chegue a um consenso no time: as opções do Prettier, como aspas simples ou duplas, devem ser decididas em conjunto, e não por uma única pessoa.
  3. Priorize o desempenho: execute apenas as verificações necessárias no hook de pre-commit e deixe os testes complexos para a CI.
  4. Atualize regularmente: acompanhe as mudanças de versão do Next.js e do ESLint, principalmente a futura remoção do comando next lint no Next.js 16.

Próximas ações

Se você ainda não configurou essa cadeia de ferramentas no projeto, recomendo experimentar agora. Siga este artigo passo a passo e tudo ficará pronto em cerca de meia hora.

Depois, compartilhe a configuração com o time para padronizar o ambiente de desenvolvimento.

Por fim, ajuste as regras do Prettier e do ESLint à realidade da equipe. Lembre-se: as ferramentas devem servir às pessoas, e não o contrário.

Minha experiência

Sinceramente, configurar essa cadeia de ferramentas parece trabalhoso no início. Eu mesmo demorei um bom tempo para resolver os problemas da migração para o flat config do ESLint 9. Depois que comecei a usá-la, porém, não quis mais voltar atrás.

Hoje, quando faço um commit, não preciso me preocupar com a formatação nem com a possibilidade de esquecer de executar o lint. O hook de pre-commit verifica tudo automaticamente, e essa tranquilidade é excelente.

A eficiência do PR review do time também melhorou bastante. Antes, as pessoas discutiam no PR se determinado trecho deveria usar aspas simples ou duplas. Isso não acontece mais, porque o Prettier já padronizou tudo. Podemos investir nosso tempo na lógica de negócio e na arquitetura, em vez de discutir detalhes de formatação.

O ganho de eficiência proporcionado por essa automação compensa o tempo necessário para configurá-la.


Espero que este artigo ajude você. Se encontrar algum problema durante a configuração, deixe um comentário e farei o possível para ajudar.

Boa configuração!

15 min de leitura · Publicado em: 6 jan 2026 · Atualizado em: 8 set 2026

Comentários

Entre com GitHub para comentar

Easton BlogEaston Blog