Quick Summary
This post covers various Vue project structures suitable for different project sizes:
- Flat structure for small projects
- Atomic Design for scalable applications
- Modular approach for larger projects
- Feature Sliced Design for complex applications
- Microfrontends for enterprise-level solutions
Table of Contents
Open Table of Contents
- Introduction
- 1. Flat Structure: Perfect for Small Projects
- 2. Atomic Design: Scalable Component Organization
- 3. Modular Approach: Feature-Based Organization
- 4. Feature-Sliced Design: For Complex Applications
- 5. Microfrontends: Enterprise-Level Solution
- Conclusion
- General Rules and Best Practices
- Additional Resources
Introduction
When starting a Vue project, one of the most critical decisions you’ll make is how to structure it. The right structure enhances scalability, maintainability, and collaboration within your team. This consideration aligns with Conway’s Law:
“Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations.”
— Mel Conway
In essence, your Vue application’s architecture will reflect your organization’s structure, influencing how you should plan your project’s layout.
Whether you’re building a small app or an enterprise-level solution, this guide covers various project structures suited to different scales and complexities.
1. Flat Structure: Perfect for Small Projects
Are you working on a small-scale Vue project or a proof of concept? A simple, flat folder structure might be the best choice to keep things straightforward and avoid unnecessary complexity.
Click to view folder structure
/src
|-- /components
| |-- BaseButton.vue
| |-- BaseCard.vue
| |-- PokemonList.vue
| |-- PokemonCard.vue
|-- /composables
| |-- usePokemon.js
|-- /utils
| |-- validators.js
|-- /layout
| |-- DefaultLayout.vue
| |-- AdminLayout.vue
|-- /plugins
| |-- translate.js
|-- /views
| |-- Home.vue
| |-- PokemonDetail.vue
|-- /router
| |-- index.js
|-- /store
| |-- index.js
|-- /assets
| |-- /images
| |-- /styles
|-- /tests
| |-- ...
|-- App.vue
|-- main.js
Pros and Cons
✅ Pros | ❌ Cons |
---|---|
Easy to implement | Not scalable |
Minimal setup | Becomes cluttered as the project grows |
Ideal for small teams or solo developers | Lack of clear separation of concerns |
2. Atomic Design: Scalable Component Organization
For larger Vue applications, Atomic Design methodology can be advantageous. This approach organizes components into a hierarchy from simplest to most complex.
The Atomic Hierarchy
- Atoms: Basic elements like buttons and icons.
- Molecules: Groups of atoms forming simple components (e.g., search bars).
- Organisms: Complex components made up of molecules and atoms (e.g., navigation bars).
- Templates: Page layouts that structure organisms without real content.
- Pages: Templates filled with real content to form actual pages.
This method ensures scalability and maintainability, facilitating a smooth transition between simple and complex components.
Click to view folder structure
/src
|-- /components
| |-- /atoms
| | |-- AtomButton.vue
| | |-- AtomIcon.vue
| |-- /molecules
| | |-- MoleculeSearchInput.vue
| | |-- MoleculePokemonThumbnail.vue
| |-- /organisms
| | |-- OrganismPokemonCard.vue
| | |-- OrganismHeader.vue
| |-- /templates
| | |-- TemplatePokemonList.vue
| | |-- TemplatePokemonDetail.vue
|-- /pages
| |-- PageHome.vue
| |-- PagePokemonDetail.vue
|-- /composables
| |-- usePokemon.js
|-- /utils
| |-- validators.js
|-- /layout
| |-- LayoutDefault.vue
| |-- LayoutAdmin.vue
|-- /plugins
| |-- translate.js
|-- /router
| |-- index.js
|-- /store
| |-- index.js
|-- /assets
| |-- /images
| |-- /styles
|-- /tests
| |-- ...
|-- App.vue
|-- main.js
Pros and Cons
✅ Pros | ❌ Cons |
---|---|
Highly scalable | Can introduce overhead in managing layers |
Organized component hierarchy | Initial complexity in setting up |
Reusable components | Might be overkill for smaller projects |
Improves collaboration among teams |
3. Modular Approach: Feature-Based Organization
As your project scales, consider a Modular Monolithic Architecture. This structure encapsulates each feature or domain, enhancing maintainability and preparing for potential evolution towards microservices.
Click to view folder structure
/src
|-- /core
| |-- /components
| | |-- BaseButton.vue
| | |-- BaseIcon.vue
| |-- /models
| |-- /store
| |-- /services
| |-- /views
| | |-- DefaultLayout.vue
| | |-- AdminLayout.vue
| |-- /utils
| | |-- validators.js
|-- /modules
| |-- /pokemon
| | |-- /components
| | | |-- PokemonThumbnail.vue
| | | |-- PokemonCard.vue
| | | |-- PokemonListTemplate.vue
| | | |-- PokemonDetailTemplate.vue
| | |-- /models
| | |-- /store
| | | |-- pokemonStore.js
| | |-- /services
| | |-- /views
| | | |-- PokemonDetailPage.vue
| | |-- /tests
| | | |-- pokemonTests.spec.js
| |-- /search
| | |-- /components
| | | |-- SearchInput.vue
| | |-- /models
| | |-- /store
| | | |-- searchStore.js
| | |-- /services
| | |-- /views
| | |-- /tests
| | | |-- searchTests.spec.js
|-- /assets
| |-- /images
| |-- /styles
|-- /scss
|-- App.vue
|-- main.ts
|-- router.ts
|-- store.ts
|-- /tests
| |-- ...
|-- /plugins
| |-- translate.js
Pros and Cons
✅ Pros | ❌ Cons |
---|---|
Enhances scalability | Potential code duplication |
Encapsulated features | Can become complex if not managed properly |
Easier team collaboration | Requires discipline in module boundaries |
Prepares for future microservices transition |
4. Feature-Sliced Design: For Complex Applications
Feature-Sliced Design is ideal for big, long-term projects. This approach breaks the application into different layers, each with a specific role.
Layers of Feature-Sliced Design
- App: Global settings, styles, and providers.
- Processes: Global business processes, like user authentication flows.
- Pages: Full pages built using entities, features, and widgets.
- Widgets: Combines entities and features into cohesive UI blocks.
- Features: Handles user interactions that add value.
- Entities: Represents core business models.
- Shared: Reusable utilities and components unrelated to specific business logic.
Click to view folder structure
/src
|-- /app
| |-- App.vue
| |-- main.js
| |-- app.scss
|-- /processes
|-- /pages
| |-- Home.vue
| |-- PokemonDetailPage.vue
|-- /widgets
| |-- UserProfile.vue
| |-- PokemonStatsWidget.vue
|-- /features
| |-- pokemon
| | |-- CatchPokemon.vue
| | |-- PokemonList.vue
| |-- user
| | |-- Login.vue
| | |-- Register.vue
|-- /entities
| |-- user
| | |-- userService.js
| | |-- userModel.js
| |-- pokemon
| | |-- pokemonService.js
| | |-- pokemonModel.js
|-- /shared
| |-- ui
| | |-- BaseButton.vue
| | |-- BaseInput.vue
| | |-- Loader.vue
| |-- lib
| | |-- api.js
| | |-- helpers.js
|-- /assets
| |-- /images
| |-- /styles
|-- /router
| |-- index.js
|-- /store
| |-- index.js
|-- /tests
| |-- featureTests.spec.js
Pros and Cons
✅ Pros | ❌ Cons |
---|---|
High cohesion and clear separation | Initial complexity in understanding the layers |
Scalable and maintainable | Requires thorough planning |
Facilitates team collaboration | Needs consistent enforcement of conventions |
5. Microfrontends: Enterprise-Level Solution
Microfrontends take the concept of microservices to the frontend. Different teams can work on various sections of a web app independently, allowing for flexible development and deployment.
Key Components
- Application Shell: The main controller handling basic layout and routing, connecting all microfrontends.
- Decomposed UIs: Each microfrontend focuses on a specific part of the application and can be developed with different technologies.
Pros and Cons
✅ Pros | ❌ Cons |
---|---|
Independent deployments | High complexity in orchestration |
Scalability across large teams | Requires robust infrastructure |
Technology-agnostic approach | Potential inconsistencies in user experience |
Conclusion
Selecting the right project structure depends on your project’s size, complexity, and team organization. The more complex your team or project is, the more you should aim for a structure that facilitates scalability and maintainability.
Your project’s architecture should grow with your organization, providing a solid foundation for future development.
Comparison Chart
Approach | Description | ✅ Pros | ❌ Cons |
---|---|---|---|
Flat Structure | Simple structure for small projects | Easy to implement | Not scalable, can become cluttered |
Atomic Design | Hierarchical component-based structure | Scalable, organized, reusable components | Overhead in managing layers, initial complexity |
Modular Approach | Feature-based modular structure | Scalable, encapsulated features | Potential duplication, requires discipline |
Feature-Sliced Design | Functional layers and slices for large projects | High cohesion, clear separation | Initial complexity, requires thorough planning |
Microfrontends | Independent deployments of frontend components | Independent deployments, scalable | High complexity, requires coordination between teams |
General Rules and Best Practices
Before concluding, let’s highlight some general rules you can apply to every structure. These guidelines are important for maintaining consistency and readability in your codebase.
Base Component Names
Use a prefix for your UI components to distinguish them from other components.
Bad:
components/
|-- MyButton.vue
|-- VueTable.vue
|-- Icon.vue
Good:
components/
|-- BaseButton.vue
|-- BaseTable.vue
|-- BaseIcon.vue
Tightly Coupled Component Names
Group tightly coupled components together by naming them accordingly.
Bad:
components/
|-- TodoList.vue
|-- TodoItem.vue
|-- TodoButton.vue
Good:
components/
|-- TodoList.vue
|-- TodoListItem.vue
|-- TodoListItemButton.vue
Order of Words in Component Names
Component names should start with the highest-level words and end with descriptive modifiers.
Bad:
components/
|-- ClearSearchButton.vue
|-- ExcludeFromSearchInput.vue
|-- LaunchOnStartupCheckbox.vue
Good:
components/
|-- SearchButtonClear.vue
|-- SearchInputExclude.vue
|-- SettingsCheckboxLaunchOnStartup.vue
Organizing Tests
Decide whether to keep your tests in a separate folder or alongside your components. Both approaches are valid, but consistency is key.
Approach 1: Separate Test Folder
/vue-project
|-- src
| |-- components
| | |-- MyComponent.vue
| |-- views
| | |-- HomeView.vue
|-- tests
| |-- components
| | |-- MyComponent.spec.js
| |-- views
| | |-- HomeView.spec.js
Approach 2: Inline Test Files
/vue-project
|-- src
| |-- components
| | |-- MyComponent.vue
| | |-- MyComponent.spec.js
| |-- views
| | |-- HomeView.vue
| | |-- HomeView.spec.js
Additional Resources
- Official Vue.js Style Guide
- Micro Frontends - Extending Microservice Ideas to Frontend Development
- Martin Fowler on Microfrontends
- Official Feature-Sliced Design Documentation