What should a real-world Vue 3 app look like?

January 5, 2023


Two months ago I started a new role building and maintaining a Vue 2 application. As we set our sights on 2023 - we鈥檝e started to ask ourselves what a next-gen Vue 3 application might look like. What has changed in the industry over the past few years? What are the industry's best practices?
Most importantly (at this stage), how do we organize our code in an elegant way that adheres to Vue鈥檚 style guide?
During my research, I noticed a handful of patterns and practices that stood out - especially from the perspective of organization:
  1. The entrypoint is split into separate files
  1. It follows casing standards religiously
  1. Its type organization is predictable
  1. It uses next-gen state management (hint: Pinia)
  1. It makes heavy use of composables

1. The entrypoint is split into separate files

In Vue, the entrypoint is responsible for bootstrapping the app and setting up the main Vue instance. It might be named main.ts, index.ts , app-setup.ts, etc. In a large and complex application, it can get a little out of hand to keep adding bootstrap functions to this single file as your application and its dependencies grow.
In the examples I looked at, it was common practice to split this file into smaller files organized by functionality/dependency. Generally, this allows for better readability, easier debugging, and an overall cleaner structure.
I found the naming convention for where these were located to be interesting. In some instances it was /plugins/ while in others it was /modules/. I鈥檇 love to find more examples to solidify my own preference, but in the end it鈥檚 all personal/team preference.


2. It follows casing standards religiously

notion image
camelCase, kebab-case, and PascalCase are casing patterns used for naming folders and files within an application. Vue does a good job of documenting best-practices in this area.
According to the Vue docs on Single-file component filename casing:
Filenames of聽single-file components聽should either be always PascalCase or always kebab-case. PascalCase works best with autocompletion in code editors, as it's consistent with how we reference components in JS(X) and templates, wherever possible. However, mixed case filenames can sometimes create issues on case-insensitive file systems, which is why kebab-case is also perfectly acceptable.
In the examples I found, there was a mix of casing standards. Most of them favored PascalCase SFC with camelCase JS/TS. Although, my own preference after seeing all of them is the kebab-case everywhere that Directus uses (something about it just felt more cohesive).

PascalCase SFC, camelCase JavaScript/TypeScript, and kebab-case directories

PascalCase SFC and kebab-case everything else

Kebab-case everywhere

3. Type organization is predictable

By placing your global types in a central location, you can easily import and use them throughout your application. For example, if you have a global type for a user object, you can import it into any component that needs to work with user data.
This not only helps with code organization, but it also makes it easier to maintain and update types as your project evolves. Additionally, keeping your types organized in a separate folder can help to improve the readability and understanding of your code for other developers working on the project.
Finally - local types are colocated alongside or inside the files that need them.


4. It uses next-gen state management (hint: Pinia)

Using a state management system can help improve the organization and maintainability of your code, especially in larger applications with many components that need to share data. It can also make it easier to debug your application and understand how different pieces interact with one another.
In the applications that I looked at (specifically for Vue 3), I found that most projects were using Pinia. While digging around on opinions, I found a tweet that provides some context around the direction of Vue鈥檚 preferred state management library:
You can also read further about this directly in the Vue documentation (which I found later 馃榾).


5. It makes heavy use of composables (hence, the Composition API)

Vue 3 introduces a new feature called composables, which are essentially reusable pieces of logic that can be shared across components. These composables are created using a new function-based API and are designed to make it easier to share logic and functionality between components.
One of the key benefits of composables is that they can improve the readability and maintainability of your code. Since they are self-contained and can be easily imported and used in multiple components, you can avoid duplicating code and keep your components lean and focused. Composables also make it easier to test and debug your code, since you can isolate and test individual pieces of logic separately.
Overall, composables are a powerful and useful addition to the Vue ecosystem, and they are sure to become an essential tool for developers working with Vue 3. There is so much content around composables, that it warrants an entire post dedicated to their usage 馃帀

Learn More


There鈥檚 plenty more to explore鈥

These were just five of the organizational aspects I observed in a handful of open-source projects. I鈥檒l continue exploring examples of large scale, production-grade Vue 3 projects. There is a lot to cover - and I鈥檓 thoroughly enjoying the Vue ecosystem.