Vue.js 57 🟢 Nested Routes, Named Views, and Route Aliasing
A Vue application’s UI is rarely a single flat layer. A dashboard has a persistent sidebar and a main content area. A settings page has a navigation panel and a detail pane. A user profile has a header that stays while the tab content changes. Vue Router expresses these structures through three distinct mechanisms: nested routes for components inside components, named views for multiple sibling components at the same level, and aliases for making one route reachable through multiple URLs without redirecting.
The distinction between nested routes and named views is the one that trips people up. Nested routes are about hierarchy: a parent component contains a <router-view>, and the child route’s component renders inside that parent. Named views are about parallelism: a single route renders multiple components into multiple <router-view> outlets that sit side by side, not inside each other . Aliases are about identity: a route has a canonical path, and an alias makes a second path behave exactly like the first without changing the URL the user sees .
Key point: Nested routes use the children array and render inside a parent component’s <router-view>; named views use the components object (plural) and render into multiple sibling <router-view> outlets identified by name; aliases use the alias property and map an additional path to the same route record without redirecting the user.
Why nested routes, named views, and aliases exist
The layout composition problem. A settings page like /settings/profile and /settings/emails share the same navigation sidebar but display different content in the main area. The sidebar is not part of the profile component or the emails component—it is part of the parent layout. Nested routes solve this by making UserSettings the parent component that contains the sidebar and a <router-view>, and the child routes render into that <router-view> . The parent stays mounted while the child changes.
The parallel outlet problem. A layout might need three independent regions: a sidebar, a main content area, and a footer, each rendering a different component for the same route. Nested routes cannot express this because they only provide one nested outlet per parent. Named views solve it by giving each <router-view> a name and mapping each name to a component in the route’s components object . The route renders all three components simultaneously, side by side.
The canonical URL problem. A route like /users/42/profile might also be reachable as /profile/42 for legacy reasons, or /u/42/profile as a shorthand. A redirect changes the URL and triggers a new navigation. An alias keeps the URL the user typed but matches it as if they had visited the canonical path . The component renders without the URL changing, which matters for user experience and for preserving the original link.
The path nesting problem. Not every nested route needs a nested URL. A parent route might exist only to provide a component wrapper or a navigation guard, and its children might have absolute paths that start with /. Vue Router treats paths starting with / inside children as root paths, which means the component nesting is preserved but the URL is not . This is useful when the visual hierarchy and the URL hierarchy should not match.
a. Nested routes: components inside components
A nested route is defined with the children array on a parent route. The parent component must contain a <router-view> where the child renders.
// router.js
import { createRouter, createWebHistory } from 'vue-router'
import User from './User.vue'
import UserProfile from './UserProfile.vue'
import UserPosts from './UserPosts.vue'
import UserHome from './UserHome.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{
// Parent route: /user/:id
path: '/user/:id',
component: User,
children: [
// Empty path renders UserHome at /user/:id
{ path: '', component: UserHome },
// Renders inside User's <router-view> at /user/:id/profile
{ path: 'profile', component: UserProfile },
// Renders inside User's <router-view> at /user/:id/posts
{ path: 'posts', component: UserPosts },
],
},
],
})
The parent component User.vue must have its own <router-view>. Without it, the child route matches but nothing renders.
<!-- User.vue -->
<template>
<div class="user">
<!-- The :id param is available from the parent route -->
<h2>User {{ $route.params.id }}</h2>
<!-- Child routes render here -->
<router-view />
</div>
</template>
The empty path '' is the default child route. When the URL is exactly /user/42 and no further segment is present, the UserHome component renders inside User‘s outlet . Without it, visiting /user/42 would render the parent component with an empty outlet, which is usually not what the user expects.
A nested path that starts with / is treated as a root path. The component nesting is preserved—it still renders inside the parent’s <router-view>—but the URL does not include the parent segment. This is useful for grouping routes under a layout without reflecting the layout in the URL .
b. Named views: multiple outlets at the same level
Named views are defined with the components object on a single route. Each key in the object matches a name attribute on a <router-view> in the template.
<!-- App.vue -->
<template>
<div class="layout">
<!-- Renders the component mapped to "sidebar" -->
<router-view name="sidebar" class="sidebar" />
<!-- Renders the component mapped to "default" -->
<router-view class="main" />
<!-- Renders the component mapped to "footer" -->
<router-view name="footer" class="footer" />
</div>
</template>
The route maps each name to a component. The default key is used for the unnamed <router-view>.
const router = createRouter({
routes: [
{
path: '/',
components: {
// Renders to <router-view />
default: Home,
// Renders to <router-view name="sidebar" />
sidebar: MainSidebar,
// Renders to <router-view name="footer" />
footer: MainFooter,
},
},
],
})
The components option is plural. Using component singular on a route with named views is a common mistake that results in only one view rendering .
Named views can be combined with nested routes. The parent route uses component singular for the parent component, and a child route uses components plural for its own named views. The nested <router-view> inside the parent can also have a name, which is how complex layouts with multiple independent panels are built .
// Nested named views
{
path: '/settings',
component: UserSettings, // Parent component
children: [
{
path: 'profile',
components: {
default: UserProfile, // Renders to <router-view /> in UserSettings
helper: UserProfilePreview, // Renders to <router-view name="helper" />
},
},
],
}
c. Aliases: multiple paths, one route
An alias is a path that matches a route record without changing the URL. The difference from a redirect is precise: a redirect replaces the URL and triggers a new navigation; an alias keeps the URL the user typed but matches the record’s component .
const router = createRouter({
routes: [
{
path: '/',
component: Homepage,
// Visiting /home renders Homepage but URL stays /home
alias: '/home',
},
],
})
The alias can be a string or an array of strings. It can be absolute (starting with /) or relative. In nested routes, an absolute alias is often necessary to make the alias independent of the parent path .
{
path: '/users',
component: UsersLayout,
children: [
{
path: 'list',
component: UserList,
// All three URLs render UserList:
// /users/list, /people, /users
alias: ['/people', ''],
},
],
}
If the route has params, the alias must include the same params. An absolute alias that omits the param will not match correctly .
{
path: '/users/:id',
component: UsersByIdLayout,
children: [
{
path: 'profile',
component: UserDetails,
// /users/24/profile, /users/24, and /24 all render UserDetails
alias: ['/:id', ''],
},
],
}
The SEO caveat is worth noting. When a route is reachable through multiple URLs, search engines may index the alias instead of the canonical path. The Vue Router documentation recommends defining a canonical link in the page head to indicate which URL is the preferred one .
Complete Example Session
The following session builds a settings page with a nested layout, a named helper view, and an alias for a legacy URL.
// ============================================
// PART 1: THE ROUTE CONFIGURATION
// ============================================
import { createRouter, createWebHistory } from 'vue-router'
import UserSettings from './UserSettings.vue'
import UserEmails from './UserEmails.vue'
import UserProfile from './UserProfile.vue'
import UserProfilePreview from './UserProfilePreview.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{
// Parent route: /settings
path: '/settings',
component: UserSettings,
// Alias the parent so /preferences also renders UserSettings
alias: '/preferences',
children: [
// Default child: renders at /settings
{ path: '', redirect: 'profile' },
{
// Child route: /settings/emails
path: 'emails',
component: UserEmails,
},
{
// Child route with named views: /settings/profile
path: 'profile',
components: {
// Renders to the default <router-view> in UserSettings
default: UserProfile,
// Renders to <router-view name="helper" /> in UserSettings
helper: UserProfilePreview,
},
// Alias this child so /profile also works
alias: ['/profile'],
},
],
},
],
})
<!-- ============================================
PART 2: THE PARENT COMPONENT
============================================ -->
<!-- UserSettings.vue -->
<template>
<div class="settings">
<h1>User Settings</h1>
<!-- Navigation is always visible -->
<nav>
<router-link to="/settings/profile">Profile</router-link>
<router-link to="/settings/emails">Emails</router-link>
</nav>
<!-- Default child outlet: UserProfile or UserEmails -->
<router-view />
<!-- Named outlet: UserProfilePreview (only on profile) -->
<router-view name="helper" />
</div>
</template>
The route configuration uses children to nest the email and profile views inside UserSettings. The profile child uses components (plural) to render both UserProfile and UserProfilePreview at the same time. The parent route has an alias /preferences, and the profile child has an alias /profile. Visiting /preferences/profile renders the same components as /settings/profile, but the URL stays /preferences/profile.
Quick Reference
Nested Routes vs Named Views
| Aspect | Nested Routes | Named Views |
|---|---|---|
| Config key | children | components (plural) |
| Rendering | Inside parent’s <router-view> | In sibling <router-view> outlets |
| Relationship | Parent-child hierarchy | Parallel at the same level |
| Outlet name | Default (unnamed) | Matches key in components |
Nested Path Rules
| Path | Behavior |
|---|---|
'profile' | Appended to parent path |
'' | Matches parent path exactly |
'/absolute' | Root path, component still nested |
Named View Configuration
| Key | Outlet |
|---|---|
default | <router-view /> |
sidebar | <router-view name="sidebar" /> |
helper | <router-view name="helper" /> |
Redirect vs Alias
| Property | URL Changes | Component Renders | Guards |
|---|---|---|---|
redirect | Yes | At target | On target only |
alias | No | Same record | On the record |
Best Practices
✅ Do This:
// Use children for hierarchy
{ path: '/user/:id', component: User, children: [{ path: 'profile', component: Profile }] }
// Use components plural for named views
{ path: '/', components: { default: Home, sidebar: Sidebar } }
// Use empty path for default child
{ path: '', component: UserHome }
// Use alias to keep legacy URLs working
{ path: '/', component: Home, alias: '/home' }
❌ Don’t Do This:
// Using component singular with multiple outlets
{ path: '/', component: { default: Home, sidebar: Sidebar } }
// Expecting child to render without parent <router-view>
{ path: '/user', component: User, children: [{ path: 'profile', component: Profile }] } // no <router-view> in User
// Using redirect when the URL should stay the same
{ path: '/home', redirect: '/' } // URL changes to /
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Child route not rendering | Parent lacks <router-view> | Add outlet to parent component |
| Named view not rendering | Used component not components | Use plural components |
| Empty outlet at parent path | No default child | Add { path: '', component: ... } |
| Alias not matching params | Alias omits params | Include :id in alias |
| Redirect changes URL | Confused alias with redirect | Use alias not redirect |
Real-World Examples
1. Nested child route
// Renders inside User's <router-view>
{ path: '/user/:id', component: User, children: [{ path: 'profile', component: Profile }] }
2. Default child
// Renders UserHome at /user/:id
{ path: '', component: UserHome }
3. Named view configuration
// Multiple outlets for one route
{ path: '/', components: { default: Home, sidebar: Sidebar } }
4. Nested named view
// Child route with its own named outlets
{ path: 'profile', components: { default: UserProfile, helper: Preview } }
5. Absolute alias in nested route
// /people renders UserList regardless of parent
{ path: 'list', component: UserList, alias: '/people' }
6. Alias with params
// /:id matches the same route as /users/:id/profile
{ path: 'profile', component: UserDetails, alias: ['/:id', ''] }
7. Redirect vs alias
// Redirect: URL changes to /
{ path: '/home', redirect: '/' }
// Alias: URL stays /home
{ path: '/', component: Home, alias: '/home' }
8. Absolute nested path
// Component nested but URL is root-level
{ path: '/user/:id', component: User, children: [{ path: '/settings', component: Settings }] }
9. Parent redirect with children
// Parent must have component when children + redirect
{ path: '/settings', component: Settings, redirect: '/settings/profile', children: [...] }
10. Named view with nested route
<!-- UserSettings.vue -->
<router-view /> <!-- default child -->
<router-view name="helper" /> <!-- named child -->
Visual
Nested Routes
┌──────────────────────────────────────────────┐
│ User.vue (parent) │
│ ┌────────────────────────────────────────┐ │
│ │ <h2>User {{ $route.params.id }}</h2> │ │
│ │ │ │
│ │ <router-view> │ │
│ │ ┌──────────────────────────────────┐ │ │
│ │ │ UserProfile.vue (child) │ │ │
│ │ │ Renders inside parent's outlet │ │ │
│ │ └──────────────────────────────────┘ │ │
│ └────────────────────────────────────────┘ │
└──────────────────────────────────────────────┘
Named Views
┌──────────────────────────────────────────────┐
│ App.vue │
│ ┌────────┐ ┌────────────────┐ ┌────────┐ │
│ │sidebar │ │ default │ │ footer │ │
│ │ outlet │ │ outlet │ │ outlet │ │
│ └────────┘ └────────────────┘ └────────┘ │
│ │
│ One route → three components │
│ components: { default, sidebar, footer } │
└──────────────────────────────────────────────┘
Redirect vs Alias
┌──────────────────────────────────────────────┐
│ REDIRECT │
│ Visit /home → URL becomes / → renders Home │
│ URL: /home ❌ │
│ URL: / ✅ │
│ │
│ ALIAS │
│ Visit /home → URL stays /home → renders Home│
│ URL: /home ✅ │
└──────────────────────────────────────────────┘
Named Views with Nested Routes
┌──────────────────────────────────────────────┐
│ UserSettings.vue │
│ ┌────────────────────────────────────────┐ │
│ │ <h1>User Settings</h1> │ │
│ │ <nav>...</nav> │ │
│ │ │ │
│ │ <router-view /> ← default child │ │
│ │ <router-view name="helper" /> ← helper │ │
│ └────────────────────────────────────────┘ │
│ │
│ Route: components: { default, helper } │
└──────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| Nested routes | children array, parent has <router-view> |
| Default child | path: '' |
| Named views | components (plural) object |
| Default view name | default |
| Nested named view | Name the nested <router-view> |
| Alias | alias property, URL unchanged |
| Redirect | redirect property, URL changes |
| Absolute nested path | Starts with /, component still nested |
| Alias with params | Must include params in alias |
Key takeaways:
- Nested routes render inside the parent. The parent component must contain a
<router-view>, and thechildrenarray defines the routes that render into it . - Named views render side by side. The
componentsobject maps each<router-view name="...">to a component. The unnamed outlet uses thedefaultkey . - An empty path is the default child.
{ path: '', component: Home }renders when the parent path matches exactly, preventing an empty outlet . - Paths starting with
/are root-level. The component is still nested, but the URL does not include the parent segment . - Aliases keep the URL unchanged. A user visiting the alias sees the alias URL, but the route matches the original record. A redirect changes the URL .
- Aliases with params must include the params. An absolute alias that omits
:idwill not match the param route correctly . - Named views can be nested. A child route can use
componentsto render multiple views into a parent component’s named outlets .
Remember: Nested routes, named views, and aliases solve three different problems. Nested routes answer “where does this component render?”—inside the parent. Named views answer “how do I render multiple components at once?”—through parallel outlets. Aliases answer “how do I make this route reachable from another URL without changing the URL?”—by matching the record under a second path. The first is about hierarchy, the second is about parallelism, and the third is about identity. Confusing them produces layouts that do not compose, URLs that break when shared, and components that render in the wrong outlet.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!