The Perfect Guide to Setting Up a New Nuxt Project

- Lire en français

Every time I create a new Nuxt project, I follow specific steps to ensure an optimal setup. I've been working with Nuxt since 2019 and have developed specific habits when initiating new projects.

Through my experience, I've explored numerous modules and reviewed projects from both experts and beginners. This has given me a solid understanding of what works well in the Nuxt ecosystem. Setting up a new project can be daunting, especially for newcomers, so I've decided to share this guide to help you set up your Nuxt project as efficiently as possible.

Creating a New Nuxt Project

Let's begin with creating a new Nuxt project. This is the simplest step, requiring just one command:

bash
npx nuxi@latest init <project-name>

Tip

You can also create a v4 ready project with npx nuxi init nuxt-app -t v4-compat, avoiding the need for Prepare for Nuxt 4.

Note

I always choose pnpm as my package manager. You can select the one you prefer, but I recommend trying pnpm.

Running this command will scaffold a new Nuxt project within the <project-name> directory. The app is minimalistic—no configuration, no modules, just Nuxt and an app.vue file.

Update the Dependencies

Before proceeding, it's essential to update dependencies to their latest versions. This ensures you can leverage the newest features and bug fixes while avoiding issues that outdated dependencies might cause. Execute the following command to update them:

bash
npx taze -w

The taze package, developed by Anthony Fu, updates all dependencies to their latest versions. It's similar to npm-check-updates but more powerful due to its adherence to semver versioning, offering both speed and reliability.

Prepare for Nuxt 4

Currently, the latest stable version of Nuxt is version 3. However, version 4 is in development and promises numerous features and enhancements. Although not officially released, you can prepare your projects for this future update by adding the following configuration in your nuxt.config.js:

ts
export default defineNuxtConfig({
  future: {
    compatibilityVersion: 4,
  }
})

This setup enables you to start developing your projects as though you're already using Nuxt 4. This foresight not only allows you to benefit from upcoming features but also minimizes the work required to upgrade when Nuxt 4 is released.

To make the most of Nuxt 4, create a new app folder and move the app.vue file into it:

bash
mkdir app && mv app.vue app

Tip

You can also create a v4 ready project by using the npx nuxi init nuxt-app -t v4-compat command.

Upgrading to Nuxt 4

Linting and Formatting

Nuxt provides an excellent developer experience for linting and formatting. Install both the linter and the formatter with the following command:

bash
npx nuxi module add eslint && npx @antfu/ni -D typescript

This command installs the @nuxt/eslint module, which offers a 0-config ESLint setup for Nuxt projects. Enable formatting, and it will automatically fix issues upon saving a file. I always configure it in my nuxt.config.ts:

ts
export default defineNuxtConfig({
  eslint: {
    config: {
      stylistic: true
    }
  }
})

Additionally, create a .vscode/settings.json file to disable the prettier extension, preventing conflicts with the ESLint formatter:

json
{
  "prettier.enable": false
}

Add two scripts to your package.json file:

json
{
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint --fix ."
  }
}

Now, you can run pnpm run lint to check for issues and pnpm run lint:fix to automatically fix them.

These predefined configurations make it straightforward to set up ESLint with TypeScript and Vue support, ensuring consistent and clean code.

UI and Components

With a clean project setup, the latest dependencies, preparation for Nuxt 4, and robust linting and formatting, it's time to focus on UI and components. This step varies based on project objectives and design requirements.

Nuxt UI and Nuxt UI Pro

If the project emphasizes business logic over UI, I use the Nuxt UI and Nuxt UI Pro component libraries. They are well-designed and easy to use. Reading the Nuxt UI source code is insightful, and I also have an article on building a component library with Vue.

The Complete Guide to Building a Vue.js Component Library

Note

As of writing, Nuxt UI 3 is not officially released, but it can be used in projects. If you're reading this later, let me know in the comments, and I'll update this guide.

First, install Nuxt UI and Tailwind CSS:

bash
pnpm add @nuxt/ui@next tailwindcss@next

Add the module to your nuxt.config.ts file:

ts
export default defineNuxtConfig({
  modules: ['@nuxt/ui']
})

Import necessary CSS in your app/assets/css/main.css file:

css
@import "tailwindcss";
@import "@nuxt/ui";

Ensure this CSS file is included in the nuxt.config.ts file:

ts
export default defineNuxtConfig({
  css: ['~/assets/css/main.css']
})

Update your .vscode/settings.json file to enhance experience with the Tailwind CSS IntelliSense extension:

json
{
  "files.associations": {
    "*.css": "tailwindcss"
  },
  "editor.quickSuggestions": {
    "strings": "on"
  }
}

Lastly, modify your app/app.vue file to include the Nuxt UI component <UApp>, automatically injecting global components:

vue
<template>
  <UApp>
    <NuxtPage />
  </UApp>
</template>

Note

Nuxt UI Pro is a paid extension offering layout components for rapid app development. It's a worthwhile investment that saves time and effort, while supporting the Nuxt team and open-source development. 💚

Tailwind CSS

For projects requiring specific designs or when collaborating with designers, I turn to Tailwind CSS. It's a utility-first CSS framework that streamlines the design process to such an extent that working without it is unimaginable. The upcoming version, Tailwind CSS 4, includes an indispensable Vite plugin, eliminating the need for additional modules and simplifying the setup.

Install the latest Tailwind CSS version:

bash
pnpm add tailwindcss@next @tailwindcss/vite

Create an app/assets/css/main.css file and import Tailwind CSS:

css
@import "tailwindcss";

Update your nuxt.config.ts file to utilize the Vite plugin:

ts
import Tailwind from '@tailwindcss/vite'

export default defineNuxtConfig({
  css: ['~/assets/css/main.css'],
  vite: {
    plugins: [
      Tailwind()
    ]
  }
})

Enhance your developer experience by updating your .vscode/settings.json file for the Tailwind CSS IntelliSense extension:

json
{
  "files.associations": {
    "*.css": "tailwindcss"
  },
  "editor.quickSuggestions": {
    "strings": "on"
  }
}

The setup is incredibly straightforward!

Icons

Incorporating icons into your project is essential, albeit deceptively complex. Anthony Fu's article elaborates on finding the perfect icon solution.

If utilizing Nuxt UI, icons are already included. You can safely skip this section.

For Tailwind CSS users, two options are available:

  1. Use the Nuxt Icons module provides access to over 200,000 icons from various icon sets:
bash
npx nuxi module add icon

This is the simplest solution and with the latest improvements from the v1 release, it's a powerful choice. I recommend starting with this option.

  1. Use the Tailwind CSS plugin, Tailwind CSS Icons, offers similar icons via a different approach:
bash
npx @antfu/ni -D @egoist/tailwindcss-icons

Create a tailwind.config.js file and include the plugin:

js
import { getIconCollections, iconsPlugin } from '@egoist/tailwindcss-icons'

/** @type {import('tailwindcss').Config} */
module.exports = {
  plugins: [
    iconsPlugin({
      collections: getIconCollections([/** ... */]),
    }),
  ],
}

Import the configuration in your app/assets/css/main.css file:

css
@import "tailwindcss";
@config "../../../tailwind.config.js";

I personally prefer the second solution due to its uniform setup across projects, including non-Nuxt ones, and at the time I made this choice, the Nuxt Icons module was suffering from many drawbacks. However, that's not the case anymore and I highly recommend you to start with Nuxt Icons.

Fonts

Fonts define your project's personality and influence user perception. Nuxt provides a solution: Nuxt Fonts. This zero-config module automatically loads required fonts by scanning CSS files. Installation is straightforward:

bash
npx nuxi module add fonts

This module is part of my projects unless I'm using Nuxt UI, where it's included. But I have to say that I rarely need to install it since Nuxt UI suffices for most scenarios.

CI

For personal projects, I use GitHub and always set up a CI to enforce linting and autofix errors. This approach ensures clean, consistent code. While linters and formatters are great, they're useless if unused.

I utilize GitHub Actions, detailed in a .github/workflows/ci.yml file:

yaml
name: CI

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  lint:
    name: Lint
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
      - run: corepack enable
      - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4
        with:
          node-version: 22
          cache: pnpm

      - name: Install dependencies
        run: pnpm install

      - name: Lint files
        run: pnpm run lint

To automate code formatting and commits, I use autofix.ci:

yaml
name: autofix.ci # needed to securely identify the workflow

on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read

jobs:
  autofix:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
      - run: corepack enable
      - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
        with:
          node-version: 20.5
          cache: pnpm

      - name: Install dependencies
        run: pnpm install

      - name: Lint & Fix
        run: pnpm run lint:fix

      - uses: autofix-ci/action@ff86a557419858bb967097bfc916833f5647fa8c

Keep Dependencies Up-to-date

Maintaining up-to-date dependencies is crucial. With numerous projects, this can be time-consuming. I use Renovate in each project to automate dependency updates:

Create a renovate.json file with:

json
{
  "extends": [
    "github>nuxt/renovate-config-nuxt"
  ]
}

This tool is indispensable, and I find it challenging to work on projects lacking Renovate (like some work projects).

Tips, Tricks, and Additional Considerations

Here are some extra tips and tricks I find valuable, even if not directly related to the setup:

Always Place Scripts First

Organize vue files by placing the script section first. This offers clarity by presenting component logic before the template:

vue
<script lang="ts">
// ...
</script>

<template>
  // ...
</template>

Embrace TypeScript

I advocate using TypeScript across all vue files and utility or composable scripts. Adding lang="ts" even without TypeScript code enhances the developer experience:

vue
<script lang="ts" setup>
// ...
</script>

Note

Always opt for the setup syntax in components.

Avoid Using process.env in nuxt.config.ts

Refrain from directly accessing process.env in nuxt.config.ts. For instance, assigning defaults for runtimeConfig shouldn't use process.env:

ts
export default defineNuxtConfig({
  runtimeConfig: {
    apiUrl: ''
  }
})

Tip

Hover over the apiUrl key in your IDE for environment variable hints. Nuxt provides complex typing, such as NUXT_API_URL.

Create an .env file at the project's root to define environment variables:

NUXT_API_URL=https://api.example.com

Exclude the .env file using .gitignore:

bash
echo ".env" >> .gitignore

Provide a .env.example file to guide other developers:

NUXT_API_URL=https://api.example.com
Runtime Config: The Common Mistakes

Audit Before Installing Modules

Conduct an audit before adding new modules to evaluate necessity and functionality. Sometimes, it's possible to proceed without them or to choose a superior alternative. Avoid basing decisions on stars or downloads. Instead, peruse documentation, source code, issues, and PRs for a comprehensive quality assessment. The Nuxt ecosystem evolves rapidly, and some modules may become outdated or incompatible with newer Nuxt versions.

Choosing Between useFetch and $fetch

Avoid using fetch directly; opt for $fetch, an enhanced instance of ofetch. Distinguish usage as follows:

  1. Use $fetch for client-side operations, such as form data submissions.
  2. Use useFetch where server-side rendering is feasible, like fetching API data to display on pages.

The Perfect Setup is Yours

This guide embodies everything I do to initialize a new Nuxt project. This comprehensive setup takes around 10 minutes, resulting in a clean, powerful, and future-ready project that allows focusing on business logic without distractions.

Warning

Avoid creating a template project from this guide. The ecosystem is dynamic, and new modules swiftly emerge. Each project might necessitate nuanced adjustments. This guide is a starting point, a checklist for initial setup. However, always adapt to the specific project needs. Maintaining a template demands effort and is generally not worthwhile.

I hope this guide enhances your Nuxt project setup. If you have questions or want to share your configuration, please leave a comment below.

Profil Picture of Estéban

Thanks for reading! My name is Estéban, and I love to write about web development.

I've been coding for several years now, and I'm still learning new things every day. I enjoy sharing my knowledge with others, as I would have appreciated having access to such clear and complete resources when I first started learning programming.

If you have any questions or want to chat, feel free to comment below or reach out to me on Bluesky, X, and LinkedIn.

I hope you enjoyed this article and learned something new. Please consider sharing it with your friends or on social media, and feel free to leave a comment or a reaction below—it would mean a lot to me! If you'd like to support my work, you can sponsor me on GitHub!

Support my work
Follow me on