Appearance
Folder Structure
Project Structure Overview
A well‑organized Vue 3 project structure helps maintain clarity, modularity, and scalability. Below is a recommended folder structure that aligns with modern Vue 3 conventions and best practices.
Project Structure
[APP]represents your project root directory. Placeholders like<MODULE>,<intent>, and<name>represent your actual module, intent, or file names.
[APP]
├── public/ # Publicly served static files
│ └── assets/ # Static assets (images, fonts)
├── src/
│ ├── assets/ # Shared application assets bundled with the build (not publicly addressable)
│ ├── clients/ # API client wrappers and helpers
│ ├── components/ # Reusable shared Vue components
│ │ ├── icons/ # Icon components
│ │ ├── layout/ # Layout components (e.g., Header.vue)
│ │ └── <intent>/ # Shared components by role (forms, modals, feedback, navigation, etc.)
│ ├── composables/ # Reusable composition functions
│ │ └── <name>.ts # Example composable file
│ ├── config/ # Shared configuration files (env, routes, etc.)
│ │ └── <domain>.ts # Domain-specific config (e.g., api.ts, dates.ts)
│ ├── locales/ # Internationalization files (Optional)
│ │ └── <LANGUAGE>/ # Example locale folder
│ │ └── <MODULE>.json # Example locale file by module
│ ├── models/ # Application interfaces and types
│ ├── pages/ # Page components (root level)
│ │ ├── About.vue # Example page component
│ │ ├── Home.vue # Example page component
│ │ └── <MODULE>/ # Module specific page components
│ │ ├── components/ # Component library for the feature
│ │ └── composables/ # Module-only composables (optional)
│ ├── plugins/ # Vue plugins and global configurations
│ ├── queries/ # Query definitions (server state)
│ ├── router/ # Vue Router (routes.ts, guards.ts)
│ ├── services/ # Business logic and service layer
│ │ ├── api/ # API communication layer and client
│ │ │ └── models/ # API response DTOs
│ │ └── <MODULE>/ # Module-specific service implementations
│ ├── stores/ # Pinia stores for client-side state
│ │ └── <MODULE>/ # Module-specific store
│ ├── types/ # Shared utility types and global TypeScript declarations
│ ├── utils/ # General utility functions
│ └── main.ts # Main application entry point
└── tests/
├── e2e/ # End-to-end tests
│ └── <MODULE>/ # Module-specific e2e test files
├── fixtures/ # Shared static or semi-static test data used to run tests
├── mocks/ # Simulated implementations of functions, modules, or APIs used during tests
├── stubs/ # Minimal fake components/services
└── utils/ # Test utilities/helper functionsDirectory Purpose
| Directory | Purpose | See also |
|---|---|---|
public/assets/ | Static files served directly by URL (not processed by the build) | — |
src/assets/ | Files processed by the build (hashed, optimized) | — |
src/clients/ | API client wrappers and HTTP helpers (e.g., Axios/fetch instances) | — |
src/components/icons/ | Shared icon components | 01.Naming |
src/components/layout/ | Layout components (Header, Footer, Sidebar) | 03.Components |
src/components/<intent>/ | Shared components grouped by role (forms, navigation, feedback) | 03.Components |
src/composables/ | Reusable composition functions (use<Name>.ts) | 04.Composables |
src/config/ | Shared configuration files (env, routes, Pinia setup) | 01.Naming |
src/locales/ | Internationalization files (optional) | — |
src/models/ | Domain types and interfaces (e.g., User, Order) | 01.Naming |
src/pages/<MODULE>/ | Page components; each module is self-contained | 01.Naming, 03.Components |
src/pages/<MODULE>/components/ | Module-scoped components (not shared) | 03.Components |
src/pages/<MODULE>/composables/ | Module-scoped composables (not shared) | 04.Composables |
src/plugins/ | Vue plugin registration and global configuration (e.g., app.use(...) setup) | — |
src/queries/ | Query and mutation definitions for server state | 05.Queries-Mutations |
src/router/ | Vue Router configuration (routes, guards) | 08.Routing |
src/services/api/ | API communication layer and response DTOs | 01.Naming |
src/services/<MODULE>/ | Module-specific business logic and service implementations | 06.State-Management |
src/stores/<MODULE>/ | Pinia stores for client-side state | 06.State-Management |
src/types/ | Shared utility types and global .d.ts declarations | 01.Naming |
src/utils/ | General utility functions | 01.Naming |
src/main.ts | Application entry point; mounts the Vue app | 06.State-Management |
tests/e2e/ | End-to-end tests organized by module under tests/e2e/<ModuleName>/ | 09.Testing |
tests/fixtures/ | Shared static or semi-static test data; project-specific fixtures may be colocated with their test | 09.Testing, 01.Naming |
tests/mocks/, tests/stubs/ | Test mocks and stubs (optional; depends on testing setup) | 09.Testing |
tests/helpers/ | Shared action-oriented test flows and utilities (optional; depends on testing setup) | 09.Testing |
Guidelines for Use
- Keep each module self-contained under
pages/<MODULE>, with colocatedcomponents/andcomposables/. - Place shared logic in
utils/orservices/, not in stores or pages. - Use
models/for domain-wide types; keep store-specific types colocated with the store. public/holds files served directly by URL;src/assets/holds files processed by the build (hashed, optimized). Put nothing inpublic/that the build should transform.- Don't create "bucket" folders without clear responsibility — every folder must have a defined purpose.
- Colocate page-specific components and composables under
pages/<MODULE>/components/andpages/<MODULE>/composables/. Move them tosrc/components/<domain>/orsrc/composables/when reused across modules. See 03.Components and 13.Decision-Matrix for the full decision rules. models/holds domain types and interfaces (e.g.,User,Order).types/holds shared utility types and global.d.tsdeclarations. See 01.Naming for naming rules.
See Also
For placement decisions (services vs utils vs composables vs stores), see the Decision Matrix.
Rationale
- Modularity — each module owns its pages, components, composables, and store slice. Changes to one module stay local.
- Discoverability — a consistent layout means any developer can locate a file by convention, not by search.
- No bucket folders — every directory has a single, clear purpose. Ambiguous catch-all folders accumulate unrelated code.
- Colocation — page-specific code lives beside the page it serves. Shared code lives in dedicated directories. This makes imports predictable and reduces cross-module coupling.
- Separation of concerns — server-state queries, client-state stores, business-logic services, and UI components each have their own home.