Settings Navigation Configuration in the Tanstack Start Supabase SaaS Kit
Configure the dedicated settings-section sidebar, which adapts to whether a personal or team account is active.
The settings section has its own sidebar, separate from the main application navigation. Its menu is built from the active account at apps/web/src/components/settings/settings-navigation.tsx: a personal account shows a "Your Account" group, while a team shows a group labelled with the team's name.
No account slug
The active account (personal or team) is resolved from the database, so every settings path is static — /settings, /settings/members, /settings/billing. There is no [account] slug to substitute.
How it works
getSettingsNavigationConfig(account) inspects account.is_personal_account and returns the appropriate grouped menu. It is consumed by both the desktop SettingsSidebar and the mobile navigation so they stay in sync.
import { CreditCard, Settings, User, Users } from 'lucide-react';import * as z from 'zod';import { NavigationConfigSchema } from '@kit/ui/navigation-schema';import featureFlagsConfig from '#/config/feature-flags.config.ts';import pathsConfig from '#/config/paths.config.ts';const iconClasses = 'w-4';export function getSettingsNavigationConfig(account: { name: string | null; is_personal_account: boolean | null;}) { const routes = account.is_personal_account ? [getPersonalAccountGroup()] : [getTeamAccountGroup(account.name)]; return NavigationConfigSchema.parse({ routes, style: import.meta.env.VITE_USER_NAVIGATION_STYLE, sidebarCollapsed: import.meta.env.VITE_HOME_SIDEBAR_COLLAPSED, sidebarCollapsedStyle: import.meta.env.VITE_SIDEBAR_COLLAPSIBLE_STYLE, });}Personal account group
function getPersonalAccountGroup() { const children = [ { label: 'common.routes.profile', path: pathsConfig.app.settings, Icon: <User className={iconClasses} />, highlightMatch: `${pathsConfig.app.settings}$`, }, featureFlagsConfig.enablePersonalAccountBilling ? { label: 'common.routes.billing', path: pathsConfig.app.settingsBilling, Icon: <CreditCard className={iconClasses} />, } : undefined, ].filter((route) => !!route); return { label: 'common.routes.yourAccount', children };}Team account group
The group label is the active team's name; billing respects the team billing feature flag.
function getTeamAccountGroup(accountName: string | null) { const children = [ { label: 'common.routes.settings', path: pathsConfig.app.settings, Icon: <Settings className={iconClasses} />, highlightMatch: `${pathsConfig.app.settings}$`, }, { label: 'common.routes.members', path: pathsConfig.app.settingsMembers, Icon: <Users className={iconClasses} />, }, featureFlagsConfig.enableTeamAccountBilling ? { label: 'common.routes.billing', path: pathsConfig.app.settingsBilling, Icon: <CreditCard className={iconClasses} />, } : undefined, ].filter((route) => !!route); return { label: accountName ?? 'common.routes.settings', children };}Adding a settings route
Add an item to the relevant group. New settings pages are static and live under /settings:
function getTeamAccountGroup(accountName: string | null) { const children = [ // ... existing items { label: 'Integrations', path: '/settings/integrations', Icon: <Plug className={iconClasses} />, }, ].filter((route) => !!route); return { label: accountName ?? 'common.routes.settings', children };}Team-only settings pages should redirect a personal active account away, e.g. in the route's beforeLoad:
beforeLoad: ({ context }) => { if (context.workspace.account.is_personal_account) { throw redirect({ to: pathsConfig.app.settings }); }},Route Properties
| Property | Type | Required | Description |
|---|---|---|---|
label | string | Yes | Display text (i18n key or, for a team, the team name) |
path | string | Yes | Static settings path |
Icon | ReactNode | No | Lucide icon component |
highlightMatch | string | No | Regex for active highlighting (use on the index item) |
Best Practices
- Gate by account type: use
account.is_personal_accountto decide which group/items to show, not the URL. - Use
pathsConfig: referenceapp.settings*paths instead of string literals. - Respect feature flags: gate billing items on
enablePersonalAccountBilling/enableTeamAccountBilling. - Guard team-only pages: redirect a personal active account to
/settings.
Related Topics
- Application Navigation - Configure the main sidebar
- Paths Configuration - Centralized path management