Personal Account Navigation in Next.js Supabase

Configure the personal account sidebar navigation, layout style, and menu structure in the Next.js Supabase SaaS Kit.

The personal account navigation at apps/web/config/personal-account-navigation.config.tsx defines the sidebar menu for personal workspaces. Add your own routes here to extend the dashboard navigation.

Layout Options

VariableOptionsDefaultDescription
NEXT_PUBLIC_USER_NAVIGATION_STYLEsidebar, headersidebarNavigation layout style
NEXT_PUBLIC_HOME_SIDEBAR_COLLAPSEDtrue, falsefalseStart with collapsed sidebar
NEXT_PUBLIC_SIDEBAR_COLLAPSIBLE_STYLEoffcanvas, icon, noneiconHow sidebar collapses
NEXT_PUBLIC_USER_NAVIGATION_STYLE=sidebar

Shows a vertical sidebar on the left with expandable sections.

Header Style

NEXT_PUBLIC_USER_NAVIGATION_STYLE=header

Shows navigation in a horizontal header bar.

Collapse Behavior

Control how the sidebar behaves when collapsed:

# Icon mode: Shows icons only when collapsed
NEXT_PUBLIC_SIDEBAR_COLLAPSIBLE_STYLE=icon
# Offcanvas mode: Slides in/out as an overlay
NEXT_PUBLIC_SIDEBAR_COLLAPSIBLE_STYLE=offcanvas
# None: Sidebar cannot be collapsed
NEXT_PUBLIC_SIDEBAR_COLLAPSIBLE_STYLE=none

Default Configuration

The kit ships with these routes:

import { CreditCard, Home, User } from 'lucide-react';
import { z } from 'zod';
import { NavigationConfigSchema } from '@kit/ui/navigation-schema';
import featureFlagsConfig from '~/config/feature-flags.config';
import pathsConfig from '~/config/paths.config';
const iconClasses = 'w-4';
const routes = [
{
label: 'common:routes.application',
children: [
{
label: 'common:routes.home',
path: pathsConfig.app.home,
Icon: <Home className={iconClasses} />,
end: true,
},
],
},
{
label: 'common:routes.settings',
children: [
{
label: 'common:routes.profile',
path: pathsConfig.app.personalAccountSettings,
Icon: <User className={iconClasses} />,
},
featureFlagsConfig.enablePersonalAccountBilling
? {
label: 'common:routes.billing',
path: pathsConfig.app.personalAccountBilling,
Icon: <CreditCard className={iconClasses} />,
}
: undefined,
].filter((route) => !!route),
},
] satisfies z.infer<typeof NavigationConfigSchema>['routes'];
export const personalAccountNavigationConfig = NavigationConfigSchema.parse({
routes,
style: process.env.NEXT_PUBLIC_USER_NAVIGATION_STYLE,
sidebarCollapsed: process.env.NEXT_PUBLIC_HOME_SIDEBAR_COLLAPSED,
sidebarCollapsedStyle: process.env.NEXT_PUBLIC_SIDEBAR_COLLAPSIBLE_STYLE,
});

Adding Custom Routes

Simple Route

Add a route to an existing section:

const routes = [
{
label: 'common:routes.application',
children: [
{
label: 'common:routes.home',
path: pathsConfig.app.home,
Icon: <Home className={iconClasses} />,
end: true,
},
{
label: 'Projects',
path: '/home/projects',
Icon: <Folder className={iconClasses} />,
},
],
},
// ... rest of routes
];

New Section

Add a new collapsible section:

const routes = [
// ... existing sections
{
label: 'Your Store',
children: [
{
label: 'Products',
path: '/home/products',
Icon: <Package className={iconClasses} />,
},
{
label: 'Orders',
path: '/home/orders',
Icon: <ShoppingCart className={iconClasses} />,
},
{
label: 'Analytics',
path: '/home/analytics',
Icon: <BarChart className={iconClasses} />,
},
],
},
];

Nested Routes

Create sub-menus within a section:

const routes = [
{
label: 'Dashboard',
children: [
{
label: 'Overview',
path: '/home',
Icon: <LayoutDashboard className={iconClasses} />,
end: true,
},
{
label: 'Projects',
path: '/home/projects',
Icon: <Folder className={iconClasses} />,
children: [
{
label: 'Active',
path: '/home/projects/active',
Icon: <Play className={iconClasses} />,
},
{
label: 'Archived',
path: '/home/projects/archived',
Icon: <Archive className={iconClasses} />,
},
],
},
],
},
];

Conditional Routes

Show routes based on feature flags or user state:

const routes = [
{
label: 'common:routes.settings',
children: [
{
label: 'common:routes.profile',
path: pathsConfig.app.personalAccountSettings,
Icon: <User className={iconClasses} />,
},
// Only show billing if enabled
featureFlagsConfig.enablePersonalAccountBilling
? {
label: 'common:routes.billing',
path: pathsConfig.app.personalAccountBilling,
Icon: <CreditCard className={iconClasses} />,
}
: undefined,
].filter((route) => !!route),
},
];

Route Properties

PropertyTypeRequiredDescription
labelstringYesDisplay text (supports i18n keys)
pathstringYesRoute path
IconReactNodeNoLucide icon component
endbooleanNoExact path matching (for index routes)
childrenRoute[]NoNested routes for sub-menus

Internationalization

Route labels support i18n keys:

{
label: 'common:routes.dashboard', // Uses translation
path: '/home',
Icon: <Home className={iconClasses} />,
}

Translation files are in apps/web/public/locales/[locale]/common.json:

{
"routes": {
"dashboard": "Dashboard",
"settings": "Settings",
"profile": "Profile"
}
}

For quick prototyping, use plain strings:

{
label: 'My Projects', // Plain string
path: '/home/projects',
Icon: <Folder className={iconClasses} />,
}

Best Practices

  1. Use pathsConfig: Import paths from the configuration instead of hardcoding strings.
  2. Group logically: Put related routes in the same section.
  3. Use feature flags: Conditionally show routes based on billing plans or user permissions.
  4. Consistent icons: Use icons from lucide-react for visual consistency.

Common Pitfalls

  1. Missing end property: The home route needs end: true to prevent it from matching all paths starting with /home.
  2. Forgetting to filter undefined: When using conditional routes, always filter out undefined values with .filter((route) => !!route).
  3. Wrong icon size: Use w-4 class for icons to match the navigation style.