Skip to main content
RapidDev - Software Development Agency
lovable-issues

Implementing Nested Routes Correctly in Lovable

Nested routes in Lovable use React Router's Outlet component to render child routes inside a parent layout. Define the parent route without a trailing path element, place child routes inside it, and add an Outlet component in the parent layout where child pages should appear. This pattern enables shared navigation, sidebars, and headers across related pages.

Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate7 min read~15 minAll Lovable projects using React Router v6+March 2026RapidDev Engineering Team
TL;DR

Nested routes in Lovable use React Router's Outlet component to render child routes inside a parent layout. Define the parent route without a trailing path element, place child routes inside it, and add an Outlet component in the parent layout where child pages should appear. This pattern enables shared navigation, sidebars, and headers across related pages.

Why nested routes fail to render child pages in Lovable

Nested routes let you share a common layout (like a sidebar or header) between multiple pages without duplicating code. In React Router, you define a parent route with a layout component, and child routes render inside that layout via the Outlet component. The most common failure is forgetting to add the Outlet component in the parent layout. Without Outlet, React Router has nowhere to render the child route's component — the layout appears but the page content area is blank. Another frequent issue is incorrect route nesting in App.tsx. Child routes must be JSX children of the parent Route element. If they are placed at the same level (siblings instead of children), React Router treats them as independent routes and does not apply the parent layout.

  • Missing Outlet component in the parent layout — child routes have nowhere to render
  • Routes not properly nested — child routes are siblings instead of children of the parent Route
  • Parent route has an element with trailing path that matches too specifically
  • Child route paths are absolute instead of relative — they do not inherit the parent prefix
  • Index route missing — visiting the parent path shows nothing because no default child is defined

Error messages you might see

Child route content is blank but the layout renders

The parent layout component does not include an Outlet component. Add <Outlet /> in the location where child page content should appear.

No routes matched location "/dashboard/analytics"

The child route for 'analytics' is not nested inside the '/dashboard' parent route. Make it a JSX child of the parent Route element.

Outlet rendered outside of a Route hierarchy

The Outlet component is used in a component that is not rendered by a React Router Route element. Ensure the layout component is the element of a parent Route.

Before you start

  • A Lovable project with multiple pages that should share a common layout
  • React Router v6 (the default for all Lovable projects)
  • An understanding of which pages should share which layout elements

How to fix it

1

Create a layout component with Outlet

The layout component provides shared UI (sidebar, header) and Outlet marks where child pages render

Create a new component that contains the shared layout elements (sidebar, header, footer) and includes the Outlet component from react-router-dom where the page content should appear. The Outlet component is the placeholder that React Router fills with the matched child route's component.

Before
typescript
// No shared layout — each page duplicates the sidebar
function Dashboard() {
return (
<div className="flex">
<Sidebar />
<main>Dashboard content</main>
</div>
);
}
function Analytics() {
return (
<div className="flex">
<Sidebar />
<main>Analytics content</main>
</div>
);
}
After
typescript
import { Outlet } from "react-router-dom";
import Sidebar from "@/components/Sidebar";
export default function DashboardLayout() {
return (
<div className="flex min-h-screen">
<Sidebar />
<main className="flex-1 p-8">
{/* Child route components render here */}
<Outlet />
</main>
</div>
);
}

Expected result: The layout renders the sidebar once, and child pages appear in the Outlet area without duplicating the sidebar.

2

Nest child routes inside the parent route in App.tsx

React Router only renders child components via Outlet when routes are properly nested as JSX children

Open src/App.tsx. Wrap the child routes inside the parent Route element. The parent Route gets the layout component as its element and the base path. Child routes use relative paths (without the parent prefix). Add an index route for the default child that renders when the user visits the parent path directly.

Before
typescript
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/dashboard/analytics" element={<Analytics />} />
<Route path="/dashboard/settings" element={<Settings />} />
</Routes>
After
typescript
<Routes>
<Route path="/dashboard" element={<DashboardLayout />}>
{/* Index route: renders at /dashboard */}
<Route index element={<DashboardHome />} />
{/* Child routes: render at /dashboard/analytics etc. */}
<Route path="analytics" element={<Analytics />} />
<Route path="settings" element={<DashboardSettings />} />
</Route>
<Route path="*" element={<NotFound />} />
</Routes>

Expected result: Visiting /dashboard shows DashboardHome inside the layout. Visiting /dashboard/analytics shows Analytics inside the same layout.

3

Use relative paths in nested navigation links

Relative links automatically prepend the parent route path, so your links stay correct even if the parent path changes

In the sidebar or navigation within the layout, use relative paths for links to child routes. A Link with to='analytics' inside the /dashboard layout navigates to /dashboard/analytics. This is cleaner than hardcoding the full path and makes refactoring easier.

Before
typescript
<NavLink to="/dashboard/analytics">Analytics</NavLink>
<NavLink to="/dashboard/settings">Settings</NavLink>
After
typescript
import { NavLink } from "react-router-dom";
{/* Relative paths — automatically prepend the parent /dashboard */}
<NavLink
to="analytics"
className={({ isActive }) => isActive ? "bg-accent" : ""}
>
Analytics
</NavLink>
<NavLink
to="settings"
className={({ isActive }) => isActive ? "bg-accent" : ""}
>
Settings
</NavLink>

Expected result: Navigation links work correctly within the nested layout, with active state highlighting on the current child route.

4

Add an index route for the parent path

Without an index route, visiting /dashboard directly shows the layout but with an empty Outlet

The index route is a special child that matches when the user visits the parent path exactly (no additional path segment). It acts as the default page for the layout. Without it, navigating to /dashboard shows the sidebar but an empty content area. For complex nested routing with multiple layout levels and shared state, RapidDev's engineers have built these patterns across 600+ Lovable projects.

Before
typescript
<Route path="/dashboard" element={<DashboardLayout />}>
<Route path="analytics" element={<Analytics />} />
</Route>
After
typescript
<Route path="/dashboard" element={<DashboardLayout />}>
{/* Shows at /dashboard (no trailing path) */}
<Route index element={<DashboardHome />} />
<Route path="analytics" element={<Analytics />} />
</Route>

Expected result: Visiting /dashboard renders DashboardHome inside the layout instead of showing empty content.

Complete code example

src/components/DashboardLayout.tsx
1import { Outlet, NavLink } from "react-router-dom";
2import { LayoutDashboard, BarChart3, Settings, LogOut } from "lucide-react";
3import { useAuth } from "@/contexts/AuthContext";
4
5export default function DashboardLayout() {
6 const { signOut } = useAuth();
7
8 const linkClass = ({ isActive }: { isActive: boolean }) =>
9 `flex items-center gap-3 px-4 py-2 rounded-md transition-colors ${
10 isActive
11 ? "bg-accent text-accent-foreground font-medium"
12 : "text-muted-foreground hover:bg-accent/50"
13 }`;
14
15 return (
16 <div className="flex min-h-screen">
17 {/* Sidebar — shared across all dashboard child routes */}
18 <aside className="w-64 border-r bg-card p-4 flex flex-col">
19 <h2 className="text-lg font-semibold px-4 mb-6">Dashboard</h2>
20 <nav className="flex flex-col gap-1 flex-1">
21 {/* Relative paths — React Router prepends /dashboard */}
22 <NavLink to="." end className={linkClass}>
23 <LayoutDashboard className="h-4 w-4" />
24 Overview
25 </NavLink>
26 <NavLink to="analytics" className={linkClass}>
27 <BarChart3 className="h-4 w-4" />
28 Analytics
29 </NavLink>
30 <NavLink to="settings" className={linkClass}>
31 <Settings className="h-4 w-4" />
32 Settings
33 </NavLink>
34 </nav>
35 <button
36 onClick={signOut}
37 className="flex items-center gap-3 px-4 py-2 text-muted-foreground hover:text-foreground"
38 >
39 <LogOut className="h-4 w-4" />
40 Sign out
41 </button>
42 </aside>
43
44 {/* Main content — child routes render here via Outlet */}
45 <main className="flex-1 p-8 overflow-auto">
46 <Outlet />
47 </main>
48 </div>
49 );
50}

Best practices to prevent this

  • Always include an Outlet component in layout components — without it, child routes have nowhere to render
  • Use relative paths in child Route definitions (path='analytics' not path='/dashboard/analytics') so they inherit the parent prefix
  • Add an index route for every layout to handle the case when the user visits the parent path directly
  • Use NavLink with the end prop for the index route link to prevent it from being active on all child routes
  • Keep layouts focused — a layout should only contain shared UI like navigation, not page-specific content
  • Nest Route elements as JSX children in App.tsx — placing them as siblings creates independent routes that skip the layout

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I have a Lovable.dev project and I want to create nested routes where multiple pages share a sidebar layout. Here is my current routing: [paste your App.tsx Routes] I need these pages to share a layout with a sidebar: - /dashboard (overview) - /dashboard/analytics - /dashboard/settings Please help me: 1. Create a DashboardLayout component with Outlet 2. Restructure my routes to be properly nested 3. Add navigation links with active state in the sidebar 4. Add an index route for /dashboard

Lovable Prompt

Restructure the dashboard routes in @src/App.tsx to use nested routing. Create a @src/components/DashboardLayout.tsx with a sidebar containing NavLinks to overview, analytics, and settings. Use Outlet for the content area. Move the existing Dashboard, Analytics, and Settings pages as child routes of the layout route. Add an index route that renders the Dashboard page at /dashboard.

Frequently asked questions

What is the Outlet component in React Router?

Outlet is a placeholder component provided by React Router. When placed in a parent layout component, it renders the matched child route's component. It enables nested routing where multiple pages share a common layout.

Why is my nested route content blank even though the layout shows?

The most common cause is a missing Outlet component in the layout. Check that your layout component includes <Outlet /> where the child page content should appear.

What is an index route?

An index route matches when the user visits the parent path exactly, with no additional path segment. For example, an index route under /dashboard renders at /dashboard itself. Without an index route, the Outlet is empty at the parent path.

Should I use absolute or relative paths in nested routes?

Use relative paths for child routes (path='analytics' not path='/dashboard/analytics'). Relative paths automatically prepend the parent route's path, making the routes easier to refactor if the parent path changes.

Can I nest routes more than one level deep?

Yes. You can nest routes as deep as you need. Each level needs its own layout with an Outlet component. For example: /dashboard renders DashboardLayout, /dashboard/analytics renders AnalyticsLayout inside DashboardLayout, and /dashboard/analytics/weekly renders the content inside AnalyticsLayout.

What if I can't fix this myself?

If your app needs complex nested routing with authentication guards, role-based layouts, and dynamic segments at multiple levels, RapidDev's engineers have built these patterns across 600+ Lovable projects.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your issue.

Book a free consultation

Need help with your Lovable project?

Our experts have built 600+ apps and can solve your issue fast. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.