Introduction
Getting a Vue 3 project off the ground shouldn't feel like wrestling with build configuration and dependency management. We've all been there—hours spent tweaking webpack config files or debugging mysterious module resolution issues. The good news is that modern tooling has moved far beyond those days, and setting up a Vue 3 project: a practical Vue & Nuxt guide starts with understanding the right scaffolding approach.
In this guide, we'll walk through creating a production-ready Vue 3 project using industry best practices, tooling that the team at Expona uses across our client work, and patterns that scale from a single-page app to a full Nuxt application. We'll cover scaffolding, feature selection, debugging, and the editor setup that keeps us productive in real-world applications.
Create a Project — The Official Scaffolding Tool
The Vue team provides an official scaffolding tool that handles the heavy lifting: create-vue. This isn't a third-party wrapper or an opinionated framework starter—it's the recommended way to bootstrap a Vue project because it's maintained alongside Vue itself and reflects current best practices.
Let's start by running the scaffolding command:
npm create vue@latestWhen you run this command, you'll be prompted interactively to choose features. The prompt walks you through TypeScript, JSX, Router, State Management, and testing. This is intentional design: rather than bloating every project with dependencies you might not need, the scaffolding tool lets you opt in to exactly what your application requires.
After the prompts complete, navigate to your project directory and install dependencies:
cd my-app
npm install
npm run devAt this point, you'll have a local development server running, typically on http://localhost:5173. The project structure is minimal but intentional: a src/ directory with components, a main entry point, and an App.vue root component. Vite handles the bundling and hot module replacement, so edits to your components reflect instantly in the browser.
Why Vite? It uses native ES modules during development, which means your development server starts in milliseconds rather than seconds. The build process for production is equally fast. For teams working on e-commerce platforms, CRM systems, or real-time applications where iteration speed matters, this difference compounds over thousands of edits.
Pick Features — TypeScript, Router, Pinia, Vitest and ESLint
When the scaffolding tool prompts you for features, you're making architectural decisions. Let's break down what we typically select for a professional project and why:
TypeScript
Accept this option. TypeScript catches a category of bugs at development time that would otherwise reach production. In a Vue component, TypeScript props validation is far more robust than runtime checks. Consider a component that accepts a user object:
interface User {
id: number;
email: string;
createdAt: Date;
}
export default defineComponent({
props: {
user: {
type: Object as PropType<User>,
required: true,
},
},
setup(props) {
// TypeScript knows props.user has id, email, createdAt
console.log(props.user.email);
},
});Without TypeScript, a developer could pass a user without an email field, and the error would surface only when the component tries to render or send that email. With TypeScript, the IDE flags the issue immediately.
Router
Select Vue Router. Even if your first version feels like a single-page application, you'll almost certainly need routing as the project grows. Installing Router from the start avoids refactoring navigation logic later. The scaffolding tool sets up basic route structure:
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView,
},
{
path: '/about',
name: 'about',
component: () => import('../views/AboutView.vue'),
},
],
});Notice the lazy-loaded route in the second example. Vue Router's dynamic imports split these views into separate chunks, so users downloading the home page don't pay the bundle cost of the about page.
Pinia
Choose Pinia for state management. It's the official state library for Vue 3, and it replaces Vuex. Pinia feels more natural to Vue developers because stores are simple, composable functions rather than boilerplate-heavy classes. Here's a minimal counter store:
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
const increment = () => count.value++;
const decrement = () => count.value--;
return { count, increment, decrement };
});In your component, you use it like any composable:
const counter = useCounterStore();
console.log(counter.count); // reactiveFor larger applications handling trading data, real-time updates, or complex user workflows, Pinia's simplicity scales better than alternatives.
Vitest
Select Vitest for unit testing. It's configured for Vue out of the box and runs faster than Jest because it leverages Vite's transformation pipeline. Tests execute in parallel, and hot reload during watch mode keeps you in a fast feedback loop.
ESLint
Add ESLint for linting. The scaffolding tool sets up a reasonable config that enforces consistency without being pedantic. Over a team of engineers, this saves countless code review comments about spacing and imports.
Vue DevTools — Inspect Components, State and Performance
Once your project is running, the Vue DevTools browser extension becomes your debugging partner. Install it in Chrome or Firefox, and when you open your application's DevTools, you'll see a new Vue tab.
The Components tab shows your component hierarchy in real time. You can click any component to see its props, data, computed properties, and watchers. If you're debugging why a child component isn't updating when the parent state changes, you can inspect the props being passed and immediately spot the issue.
The State tab surfaces Pinia stores. You can inspect every store's current state, and critically, you can mutate state directly in DevTools to test how your UI responds. This is invaluable when reproducing edge cases. For example, in a ride-hailing application, you might set a driver's status to "offline" through DevTools to verify the UI gracefully handles the state without making a real API call.
The Timeline feature records component lifecycle events and state changes over time, letting you step backward and forward to understand exactly when a bug appeared. For performance-sensitive applications, the Profiler tab shows which components took longest to render and why.
Install the Vue DevTools extension through your browser's extension store or from the official devtools.vuejs.org. There's no configuration needed; it detects Vue automatically when you navigate to a Vue application in development mode.
Editor — VS Code with the Vue (Official) Extension
Your development environment should feel frictionless. We recommend VS Code with the official Vue extension (published by Vue). Here's why:
The Vue extension provides syntax highlighting for single-file components, including the template, script, and style sections. More importantly, it gives you full IntelliSense support in templates. Start typing a prop name, and the editor autocompletes it. Hover over a component to see its type signature. This safety net catches typos that would otherwise require a browser refresh to discover.
Install the extension by searching for "Vue - Official" in VS Code's extension marketplace. If you already have other Vue extensions installed, disable them to avoid conflicts.
Configure your VS Code settings to format on save. Create a .vscode/settings.json file in your project root:
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[vue]": {
"editor.defaultFormatter": "Vue.volar"
}
}This configuration tells VS Code to use the Vue extension's formatter for Vue files. Now, every time you save, your code is formatted consistently, and you never need to think about indentation or quote style again.
For TypeScript, enable strict mode in your tsconfig.json:
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true
}
}Strict mode feels restrictive initially—you'll encounter type errors you hadn't considered. But those errors are exactly the bugs we want to catch early. Teams that enforce strict mode report significantly fewer production issues related to null reference errors or type mismatches.
Common Mistakes
We've seen teams stumble in predictable ways during project setup. Here are the pitfalls:
- Skipping TypeScript to "move faster." This is false economy. The setup friction pays for itself in the first sprint when TypeScript catches bugs during development rather than in production. The real speed comes from confidence and fewer runtime errors.
- Installing too many dependencies upfront. The scaffolding tool is conservative for a reason. Don't add Axios, date libraries, or UI frameworks until you actually need them. Each dependency is maintenance burden and bundle weight. Use the Fetch API and built-in Date methods until they become a bottleneck.
- Forgetting to enable strict TypeScript mode. By default, TypeScript is permissive. A property can be null without you declaring it. This defeats much of TypeScript's value. Enable strict mode immediately and address the type errors that surface.
- Ignoring ESLint warnings. Linters are annoying until they prevent a bug. Treat lint errors as compilation errors—fix them rather than disabling the rule. The team's linting configuration is a form of collective code review.
- Not setting up EditorConfig or Prettier. In a team, inconsistent formatting wastes time in code reviews. Git diffs become noisy with whitespace changes. Use a formatter from day one.
Key Takeaways
- Use
npm create vue@latestto scaffold projects. It's the official tool, it's maintained by the Vue team, and it reflects current best practices. - Select TypeScript, Router, Pinia, Vitest, and ESLint during scaffolding. These features provide type safety, routing, state management, testing, and code consistency across the team.
- Install Vue DevTools to inspect components, state mutations, and performance in real time. It's essential for debugging.
- Use VS Code with the Vue (Official) extension. Enable format-on-save and strict TypeScript mode to catch errors early.
- Don't add dependencies speculatively. Start minimal and add libraries when they solve a real problem, not in anticipation of future needs.
- Your development setup is not a one-time task. As your application grows, revisit ESLint rules, TypeScript strictness, and testing strategy. What worked for a prototype may not work for a production SaaS platform.






Comments
Loading comments…