DEV Community

Cover image for Enforce Better Vue Architecture with ESLint
Jakub Andrzejewski
Jakub Andrzejewski

Posted on

Enforce Better Vue Architecture with ESLint

As Vue applications grow, keeping the codebase clean becomes increasingly challenging. At first, everyone follows the same conventions. But over time, you start noticing things like:

  • inconsistent component structure
  • multiple ways of solving the same problem
  • different Composition API patterns
  • imports scattered everywhere
  • code that's difficult to review and maintain

This is where ESLint becomes much more than a tool for formatting—it becomes a way to enforce your project's architecture and design patterns.

In this article, we'll explore:

  • Why ESLint is more than a linter
  • How it helps maintain a consistent architecture
  • Useful Vue-specific rules
  • Examples of enforcing project-wide patterns
  • Best practices for scaling Vue applications

Let's dive in.

🤔 ESLint Is More Than a Code Formatter

Many developers think ESLint is only used to catch things like; unused variables, missing semicolons, incorrect formatting. While that's true, ESLint can do much more.

With the right configuration, it can enforce:

  • coding conventions
  • project architecture
  • Vue best practices
  • Composition API patterns
  • import organization
  • component structure

Instead of relying on code reviews to catch inconsistencies, ESLint prevents them before the code is even merged.

🟢 What Problem Does It Solve?

Imagine a team of five developers.

One component looks like this:

<script setup>
...
</script>

<template>
...
</template>

<style>
...
</style>
Enter fullscreen mode Exit fullscreen mode

Another one:

<template>
...
</template>

<script setup>
...
</script>
Enter fullscreen mode Exit fullscreen mode

Someone uses:

watch()
Enter fullscreen mode Exit fullscreen mode

Someone else always prefers:

watchEffect()
Enter fullscreen mode Exit fullscreen mode

Some developers use relative imports:

../../../components/Button.vue
Enter fullscreen mode Exit fullscreen mode

Others use aliases:

~/components/Button.vue
Enter fullscreen mode Exit fullscreen mode

None of these are necessarily wrong... but together they create inconsistency across the project. ESLint helps eliminate these differences by enforcing one agreed-upon way of writing code.

🟢 Enforcing Vue Block Order

One of the simplest examples is keeping Vue Single File Components organized. Using the vue/block-order rule, you can define the exact order of blocks.

Example:

<template>
  ...
</template>

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

<style scoped>
  ...
</style>
Enter fullscreen mode Exit fullscreen mode

🟢 Enforcing Composition API Patterns

One of the biggest advantages of ESLint is enforcing how developers use Vue APIs.

For example, you might decide that your project should always use:

  • <script setup>
  • Composition API
  • defineProps
  • defineEmits

And avoid Options API or inconsistent component definitions. This ensures new components follow the same architecture from day one.

🟢 Restricting Specific APIs

Sometimes you want to discourage certain patterns altogether. For example, you may decide:

❌ Avoid watch() unless absolutely necessary.

Prefer:

computed()
Enter fullscreen mode Exit fullscreen mode

or

watchEffect()
Enter fullscreen mode Exit fullscreen mode

ESLint can restrict the use of specific APIs and encourage better alternatives. This keeps reactive logic predictable and easier to maintain.

🟢 Enforcing Import Conventions

Large Vue projects often suffer from inconsistent imports.

Example:

import Button from '../../../components/Button.vue'
Enter fullscreen mode Exit fullscreen mode

vs.

import Button from '~/components/Button.vue'
Enter fullscreen mode Exit fullscreen mode

ESLint can enforce:

  • path aliases
  • import ordering
  • grouped imports
  • no duplicate imports

The result is cleaner and more consistent code.

🟢 Preventing Architectural Violations

ESLint can also help enforce architectural boundaries. For example:

  • Components shouldn't access API clients directly.
  • Feature modules shouldn't import from other features.
  • UI components shouldn't depend on business logic.

Using rules such as no-restricted-imports, you can prevent these patterns entirely.

Example:

'no-restricted-imports': [
  'error',
  {
    patterns: [
      '@/api/*'
    ]
  }
]
Enter fullscreen mode Exit fullscreen mode

Now components can't accidentally bypass your intended architecture.

🟢 Creating Custom Rules for Your Team

One of ESLint's greatest strengths is extensibility.

Beyond built-in rules, you can create custom rules—or use plugins—to enforce project-specific conventions.

For example:

  • composables must start with use
  • stores must live in a dedicated folder
  • feature modules cannot import each other
  • utility functions must remain pure
  • internal design system components must be used instead of native HTML elements

As your project grows, these automated checks become far more reliable than relying solely on code reviews.

🟢 Why This Matters in Large Vue Applications

Small projects can survive without strict rules. Large projects usually can't. Consistency helps:

  • onboard new developers faster
  • simplify code reviews
  • reduce technical debt
  • prevent architectural drift
  • improve long-term maintainability

Instead of debating coding style in every pull request ESLint enforces it automatically.

🧪 Best Practices

  • Treat ESLint as an architecture tool—not just a linter
  • Enable Vue-specific rules from eslint-plugin-vue
  • Agree on project conventions early
  • Enforce Composition API patterns consistently
  • Use no-restricted-imports to protect architectural boundaries
  • Automate linting in CI/CD pipelines
  • Keep rules practical—avoid overcomplicating your configuration

📖 Learn more

If you would like to learn more about Vue, Nuxt, JavaScript or other useful technologies, checkout VueSchool by clicking this link or by clicking the image below:

Vue School Link

It covers most important concepts while building modern Vue or Nuxt applications that can help you in your daily work or side projects 😉

🧪 Advance skills

A certification boosts your skills, builds credibility, and opens doors to new opportunities. Whether you're advancing your career or switching paths, it's a smart step toward success.

Check out Certificates.dev by clicking this link or by clicking the image below:

Certificates.dev Link

Invest in yourself—get certified in Vue.js, JavaScript, Nuxt, Angular, React, and more!

✅ Summary

ESLint is much more than a tool for catching syntax errors or enforcing formatting.

As Vue applications grow, consistency becomes just as important as functionality.

By using ESLint to enforce architectural decisions, you ensure that every new piece of code follows the same standards—making your project easier to understand, review, and maintain for years to come.

Take care!
And happy coding as always 🖥️

Top comments (0)