Paths Configuration in the Tanstack Start Supabase SaaS Kit

Configure route paths for authentication, personal accounts, and team accounts in the Tanstack Start Supabase SaaS Kit. Centralized path management for consistent navigation.

The paths configuration at apps/web/config/paths.config.ts centralizes all route definitions. Instead of scattering magic strings throughout your codebase, reference paths from this single configuration file.

Slug-free, DB-backed active account

The kit does not encode the current workspace in the URL. Each user has an active account (personal or team) persisted in the database (public.user_active_account), resolved server-side by public.active_account_id(). Because of this, every authenticated path is static — there is no [account] slug to substitute. Switching workspace mutates the active-account pointer and re-runs the loaders; the URL never changes.

Default Paths

Authentication Paths

Path KeyDefault ValueDescription
auth.signIn/auth/sign-inSign in page
auth.signUp/auth/sign-upSign up page
auth.verifyMfa/auth/verifyMFA verification
auth.callback/auth/callbackOAuth callback handler
auth.passwordReset/auth/password-resetPassword reset request
auth.passwordUpdate/update-passwordPassword update completion

App Paths

These serve both personal and team accounts — the active account determines what each page renders.

Path KeyDefault ValueDescription
app.home/dashboardPost-login dashboard for the active account
app.settings/settingsSettings (profile for a personal account, team settings for a team)
app.settingsMembers/settings/membersTeam members (redirects to /settings for a personal account)
app.settingsBilling/settings/billingBilling management
app.settingsBillingReturn/settings/billing/returnBilling portal / checkout return
app.createTeam/create-teamCreate a team account
app.joinTeam/joinTeam invitation acceptance

Configuration File

import * as z from 'zod';
const PathsSchema = z.object({
auth: z.object({
signIn: z.string().min(1),
signUp: z.string().min(1),
verifyMfa: z.string().min(1),
callback: z.string().min(1),
passwordReset: z.string().min(1),
passwordUpdate: z.string().min(1),
}),
app: z.object({
home: z.string().min(1),
joinTeam: z.string().min(1),
createTeam: z.string().min(1),
settings: z.string().min(1),
settingsMembers: z.string().min(1),
settingsBilling: z.string().min(1),
settingsBillingReturn: z.string().min(1),
}),
});
const pathsConfig = PathsSchema.parse({
auth: {
signIn: '/auth/sign-in',
signUp: '/auth/sign-up',
verifyMfa: '/auth/verify',
callback: '/auth/callback',
passwordReset: '/auth/password-reset',
passwordUpdate: '/update-password',
},
app: {
home: '/dashboard',
joinTeam: '/join',
createTeam: '/create-team',
settings: '/settings',
settingsMembers: '/settings/members',
settingsBilling: '/settings/billing',
settingsBillingReturn: '/settings/billing/return',
},
});
export default pathsConfig;

Using Paths in Code

In Server Functions and Loaders

import { redirect } from '@tanstack/react-router';
import pathsConfig from '#/config/paths.config.ts';
// Redirect to sign in
throw redirect({ href: pathsConfig.auth.signIn });
// Redirect to the dashboard (renders whichever account is active)
throw redirect({ href: pathsConfig.app.home });

In Client Components

import { Link } from '@tanstack/react-router';
import pathsConfig from '#/config/paths.config.ts';
function Navigation() {
return (
<nav>
<Link to={pathsConfig.app.home}>Dashboard</Link>
<Link to={pathsConfig.app.settings}>Settings</Link>
</nav>
);
}

Reading and switching the active account

Read the active account from the workspace context; switch it with the setActiveAccountFunction server function.

import { useWorkspace } from '#/components/workspace-context.tsx';
function Header() {
const { account } = useWorkspace();
return account.is_personal_account ? <PersonalHeader /> : <TeamHeader />;
}

Adding Custom Paths

Extend the schema when adding new routes to your application. New authenticated pages are static too — scope them under /dashboard or /settings and let the active account decide what they show:

const PathsSchema = z.object({
auth: z.object({
// ... existing auth paths
}),
app: z.object({
// ... existing app paths
projects: z.string().min(1),
}),
});
const pathsConfig = PathsSchema.parse({
auth: {
// ... existing values
},
app: {
// ... existing values
projects: '/dashboard/projects',
},
});

Path Conventions

Follow these conventions when adding paths:

  1. Use lowercase with hyphens: /dashboard/my-projects not /dashboard/myProjects
  2. Keep paths static: the active account is resolved from the database, not the URL — never encode an account id or slug in a path
  3. Keep paths shallow: avoid deeply nested routes when possible
  4. Group related paths: put settings-related paths under app.settings*

Common Pitfalls

  1. Reintroducing a slug: don't add account ids/slugs to URLs. Resolve the active account server-side (active_account_id()) or from useWorkspace().
  2. Hardcoding paths: don't use string literals like '/settings'. Always import from pathsConfig for consistency.
  3. Missing trailing slash consistency: the kit doesn't use trailing slashes. Keep this consistent in your custom paths.