Setting up a Next.js Project with Essential Best practices
8 mins read
#nextjs
#developer-experience
#tools
Introduction
Setting up a Next.js project isn’t just about installing dependencies, it’s about creating a maintainable, high-quality foundation. In this guide, we’ll cover a proven setup for essential tools like Prettier, ESLint, Husky, and Commitlint to ensure consistency, catch issues early, and improve team workflows, helping you stay organized and productive.
Project Setup
Start by creating a new Next.js project:
Terminal window
pnpmcreatenext-app@latest
Name your project when prompted, and select Yes for ESLint setup.
Terminal window
✔ What is your project named? … next-template
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like your code inside a `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to use Turbopack for next dev? … No / Yes
✔ Would you like to customize the import alias (@/* by default)? … No / Yes
Creating a new Next.js app in /home/ouassim/next-template.
After the prompts, create-next-app creates a folder named after your project and installs the required dependencies.
Engine locking
Ensuring consistent Node.js versions across environments is essential for predictable functionality in both development and production. Specify the supported Node.js version in your package.json:
At the time of writing this, Next.js requires Node.js version 18.18.x or later.
package.json
{
...
"engines":{
"node":">18.8.x"
}
...
}
Second, add a .npmrc file next to package.json. This .npmrc configuration enforces the Node.js version specified in package.json, preventing incompatible Node.js versions from being used.
.npmrc
engine-strict=true
The engine-strict setting tells your package manager to stop with an error on unsupported versions. This looks like:
This is happening because the package's manifest has an engines.node field specified.
To fix this issue, install the required Node version.
Let’s create our first commit:
Terminal window
gitcommit-m'build: added engine locking'
Ignore the commit message structure for now, since we will be talking about it later on in this guide. Or jump directly to it Commitlint.
ESLint
ESLint already comes installed and pre-configured when creating a new Next.js project.
Let’s add a bit of extra configuration to make it stricter than the default settings. If you disagree with any of the rules it sets, no need to worry, it’s very easy to disable any of them manually. Use .eslintrc.json in the root directory to configure these additional rules.
Next, create a .prettierignore file that lists the different directories/files we don’t want prettier to format:
.prettierignore
node_modules
.next
Add the following scripts to format files manually or check formatting status in CI environments:
package.json
{
...
"scripts":{
...
// format all files
"format":"prettier --write .",
// check if files are formatted, this is useful in CI environments
"format:check":"prettier --check ."
},
...
}
You can now run:
Terminal window
# format files
pnpmrunformat
# check if files are formatted
pnpmrunformat:check
Tailwind CSS
In order to automatically sort tailwind classes following the class order recommended by the tailwind team, we will be adding a new plugin to prettier called prettier-plugin-tailwindcss:
Terminal window
pnpmadd-Dprettier-plugin-tailwindcss
And then update your .prettierrc file and add plugins property to it:
.prettierrc
{
"endOfLine":"lf",
"semi":false,
"singleQuote":false,
"tabWidth":2,
"trailingComma":"es5",
"plugins":["prettier-plugin-tailwindcss"]
}
Sort imports
Next up, we will be adding @ianvs/prettier-plugin-sort-imports to our prettier config , this will allow us to sort import declarations using RegEX order.
First, install it as a devDependency:
Terminal window
pnpmadd-D@ianvs/prettier-plugin-sort-imports
Then, update your .prettierrc file to be as follows:
Husky is a tool that makes it easier to use Git hooks, it provides a unified interface for managing hooks.
Install husky
Terminal window
pnpmadd--save-devhusky
husky init command
The init command is the new and recommended way of setting up husky in your project. It creates a pre-commit script in .husky/ and updates the prepare script in your package.json.
Terminal window
pnpmexechuskyinit
package.json
{
...
"scripts":{
...
"prepare":"husky"
},
...
}
Adding a New Hook
Adding a new hook is as simple as creating a file, but first, delete the existing hook (.husky/pre-commit) since we will be adding our own later on.
Add a pre-push hook for building code:
Terminal window
echo"pnpm run build">.husky/pre-push
Commitlint
As you may have noticed from the previous commit messages, they follow a specific standard we call Conventional Commits, which is a lightweight convention on top of commit messages.
These VS Code extensions streamline code formatting, linting, and Tailwind utility usage directly in your editor.
Workspace Settings
After configuring ESLint and prettier, it is time to make VS Code use them automatically. To do this first create .vscode directory in the root of your project and then add settings.json file and paste the following content to it.