---
# System prepended metadata

title: Application setup with Next.js and a robust configuration
tags: [Setup]

---

---
tags: Setup
---

# Application setup with Next.js and a robust configuration

Learn how to set up a Next.js application with useful tooling and a robust configuration. Enforce consistent standards, automate quality checks, and manage environment settings, creating a strong foundation for efficient development and seamless collaboration.

## Create a Well-Organized Workspace

I suggest structuring your workspace to mirror the application's domain and subdomains, grouping applications for easier management. For instance, `next-stack/my-app` would contain all files needed to develop and deploy the application hosted on `my-app.next-stack.com`:
```bash
mkdir next-stack && cd $_
```

## Create a Next.js Application

Run the following command and select:
- `my-app` as the name
- `No` for customize the import alias

```bash
npx create-next-app@latest --use-pnpm --typescript --eslint --tailwind --src-dir --app --turbopack
```

### tsconfig Configuration

Add the following properties to `compilerOptions` field in `tsconfig.json` file:
```json
"removeComments": true,
"forceConsistentCasingInFileNames": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"exactOptionalPropertyTypes": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"allowUnusedLabels": false,
"allowUnreachableCode": false,
```

### Add [EditorConfig](https://editorconfig.org)

Create a `.editorconfig` file:

```bash
touch .editorconfig
```

Insert the following content:
```
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
max_line_length = off
trim_trailing_whitespace = false
```

### Add [Vitest](https://vitest.dev/)

```bash
pnpm i -D vitest @vitejs/plugin-react jsdom @vitest/coverage-v8
```

Create the `vitest.config.mts` file:
```bash
touch vitest.config.mts
```

Insert the following content:
```typescript
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
 
export default defineConfig({
  plugins: [react()],
  test: {
    environment: 'jsdom',
  },
})
```

Add the `test` command to the `scripts` property in the `package.json` file:
```json
"test": "vitest",
```

### Add [Prettier](https://prettier.io/)

```bash
pnpm i -D prettier prettier-plugin-tailwindcss
```

Create the `.prettierrc` file:
```bash
touch .prettierrc
```

Insert the following configuration:
```json
{
  "plugins": ["prettier-plugin-tailwindcss"],
  "printWidth": 128,
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "singleQuote": true,
  "quoteProps": "as-needed",
  "jsxSingleQuote": true,
  "trailingComma": "none",
  "bracketSpacing": true,
  "bracketSameLine": true,
  "arrowParens": "always",
  "requirePragma": false,
  "insertPragma": false,
  "proseWrap": "preserve",
  "htmlWhitespaceSensitivity": "ignore",
  "vueIndentScriptAndStyle": false,
  "endOfLine": "lf",
  "embeddedLanguageFormatting": "auto"
}
```
If you are using WebStorm, when opening this file, a message will prompt you to use this configuration for the entire project. Select "Yes" to apply it.

Create the `.prettierignore` file:
```bash
touch .prettierignore
```

Ignore the following files and directories in the Prettier check:
```
.git/
.idea/
.vscode/
node_modules/
.next/
build/
dist/
coverage/
out/
```

Run Prettier on all files in the project:
```bash
pnpm exec prettier . --write
```
The files that appear in white have been modified, while those in grey were already properly formatted.

If you are using WebStorm, in the configurations, search for `Prettier`, select `Automatic Prettier configuration`, and check the box for `Run on save`.
![image](https://hackmd.io/_uploads/H1JA2iu4R.png)

Add the `prettier` and `prettier.ci` commands to the `scripts` property in the `package.json` file:
```json
"prettier": "prettier --write ./src/",
"prettier.ci": "prettier --check ./src/",
```

### Add [Stylelint](https://stylelint.io/)

```bash
pnpm i -D stylelint stylelint-config-standard stylelint-config-tailwindcss
```

Create the `.stylelintrc` file:
```bash
touch .stylelintrc
```

Insert the following configuration:
```json
{
  "extends": ["stylelint-config-recommended", "stylelint-config-tailwindcss"]
}
```

Run Stylelint with the `fix` option on all `css` files in the project:
```bash
pnpm exec stylelint "**/*.css" --fix
```

Add the `lint.style` command to the `scripts` property in the `package.json` file:
```json
"lint.style": "stylelint \"**/*.css\"",
```

### Configurer [ESLint](https://eslint.org/)

Install the default ESLint configurations for JS and TS:

```bash
pnpm i -D eslint @eslint/js @types/eslint__js typescript-eslint eslint-plugin-functional eslint-plugin-import eslint-config-prettier eslint-plugin-security eslint-plugin-react eslint-plugin-boundaries @vitest/eslint-plugin
```

Replace the `.eslintrc.json` file with `eslint.config.mjs`:
```bash
mv .eslintrc.json eslint.config.mjs
```

Replace the file content with:
```js
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import functional from 'eslint-plugin-functional';
import importPlugin from 'eslint-plugin-import';
import eslintConfigPrettier from 'eslint-config-prettier';
import pluginSecurity from 'eslint-plugin-security';
import react from 'eslint-plugin-react';
import boundaries from 'eslint-plugin-boundaries';
import vitest from '@vitest/eslint-plugin';

export default tseslint.config(
  {
    files: ['src/**/*.spec.ts', 'src/**/*.test.ts'],
    plugins: {
      vitest
    },
    extends: [vitest.configs.recommended],
    rules: {
      ...vitest.configs.recommended.rules
    }
  },
  {
    files: ['src/**/*.ts'],
    ignores: ['src/**/*.spec.ts', 'src/**/*.test.ts'],
    plugins: {
      boundaries
    },
    extends: [
      functional.configs.externalTypeScriptRecommended,
      functional.configs.recommended,
      functional.configs.stylistic,
    ],

  },
  {
    files: ['src/**/*.ts'],
    plugins: {
      boundaries
    },
    extends: [
      eslint.configs.recommended,
      ...tseslint.configs.strictTypeChecked,
      ...tseslint.configs.stylisticTypeChecked,
      importPlugin.flatConfigs.recommended,
      pluginSecurity.configs.recommended,
      react.configs.flat.recommended,
      react.configs.flat['jsx-runtime'],
      eslintConfigPrettier
    ],
    settings: {
      'boundaries/elements': []
    },
    rules: {
      ...boundaries.configs.recommended.rules
    },
    languageOptions: {
      parserOptions: {
        projectService: true,
        tsconfigRootDir: import.meta.dirname,
        ecmaFeatures: { jsx: true }
      }
    }
  }
);

```

Create the `.eslintignore` file:
```bash
touch .eslintignore
```

Ignore the following files and directories in Eslint check:
```
.git/
.idea/
.vscode/
node_modules/
.next/
build/
dist/
coverage/
out/
```

Rename the `lint` command to `lint.es` in the `scripts` property of the `package.json` file:
```json
"lint.es": "next lint",
```

### Add [Commitlint](https://commitlint.js.org/)

```bash
pnpm i -D @commitlint/{cli,config-conventional}
node --eval "fs.writeFileSync('.commitlintrc.mjs','export default { extends: [\'@commitlint/config-conventional\'] };')"
```

Add the `lint.commit` command to the `scripts` property in `package.json` file:
```json
"lint.commit": "commitlint --from origin/main",
```

### Add [lint-staged](https://github.com/lint-staged/lint-staged)

```bash
pnpm i -D lint-staged
```

Create `.lintstagedrc` file:
```bash
touch .lintstagedrc
```

Insert the following rules:
```json
{
  "*.(js|mjs|jsx|ts|mts|tsx)": ["eslint", "prettier --write"],
  "*.(css)": ["stylelint", "prettier --write"],
  "*.(md|json|xml|html|sh|yml|yaml)": "prettier --write"
}
```

### Add [Husky](https://typicode.github.io/husky/)

```bash
pnpm i -D husky
npx husky init
node --eval "fs.writeFileSync('.husky/pre-commit','pnpm exec lint-staged\n')"
node --eval "fs.writeFileSync('.husky/commit-msg','pnpm exec commitlint --edit \$1\n')"
```

### Add [dotenv](https://github.com/motdotla/dotenv#readme)

```bash
pnpm i dotenv
```

Create `.env.example` file:
```bash
touch .env.example
```

Add `.env` file to `.gitignore` under `# local env files`

### Make the commit for the configuration.

```bash
git add . && git commit -m"chore: application setup and configuration"
```

---

[Next](https://hackmd.io/pVySIYBOSQGH30s7hPQ_Bg)
[Home](https://hackmd.io/9GoEP2IbT6SIJQHOf03PbA)
