### Install next-safe-navigation
Source: https://github.com/lukemorales/next-safe-navigation/blob/main/README.md
Install the next-safe-navigation package using npm. You will also need to install a compatible validation library like Zod, Valibot, or ArkType.
```bash
npm install next-safe-navigation
```
```bash
# Choose one:
npm install zod # Zod (most popular)
npm install valibot # Valibot (lightweight)
npm install arktype # ArkType (fast)
```
--------------------------------
### Navigation Configuration with ArkType
Source: https://context7.com/lukemorales/next-safe-navigation/llms.txt
Example of setting up `createNavigationConfig` using ArkType for schema validation. Shows how to define routes with `params` and `search` schemas, with usage examples.
```typescript
// src/shared/navigation.ts — using ArkType
import { createNavigationConfig } from 'next-safe-navigation';
import { type } from 'arktype';
export const { routes, useSafeParams, useSafeSearchParams } =
createNavigationConfig((defineRoute) => ({
customers: defineRoute('/customers', {
search: type({
'query?': "string = ''",
'page?': 'string.numeric.parse = 1',
}),
}),
invoice: defineRoute('/invoices/[invoiceId]', {
params: type({ invoiceId: 'string' }),
}),
}));
// Usage is identical regardless of the validator used
routes.invoice({ invoiceId: 'inv_abc' });
// → '/invoices/inv_abc'
```
--------------------------------
### Install next-safe-navigation
Source: https://context7.com/lukemorales/next-safe-navigation/llms.txt
Command to install the `next-safe-navigation` package using npm.
```bash
npm install next-safe-navigation
```
--------------------------------
### Declare Routes with createNavigationConfig
Source: https://github.com/lukemorales/next-safe-navigation/blob/main/README.md
Define your application's routes and their associated parameters using `createNavigationConfig`. This example demonstrates defining routes for home, customers with search parameters, an invoice with dynamic parameters, and shop routes with catch-all segments. Ensure optional catch-all segments are marked as optional or have a default value.
```typescript
// src/shared/navigation.ts
import { createNavigationConfig } from 'next-safe-navigation';
import { z } from 'zod';
export const { routes, useSafeParams, useSafeSearchParams } =
createNavigationConfig((defineRoute) => ({
home: defineRoute('/'),
customers: defineRoute('/customers', {
search: z
.object({
query: z.string().default(''),
page: z.coerce.number().default(1),
})
.default({ query: '', page: 1 }),
}),
invoice: defineRoute('/invoices/[invoiceId]', {
params: z.object({
invoiceId: z.string(),
}),
}),
shop: defineRoute('/support/[...tickets]', {
params: z.object({
tickets: z.array(z.string()),
}),
}),
shop: defineRoute('/shop/[[...slug]]', {
params: z.object({
// ⚠️ Remember to always set your optional catch-all segments
// as optional values, or add a default value to them
slug: z.array(z.string()).optional(),
}),
}),
}));
```
--------------------------------
### Navigation Configuration with Valibot
Source: https://github.com/lukemorales/next-safe-navigation/blob/main/README.md
Configure navigation routes using `createNavigationConfig` with Valibot for schema validation. This example defines routes for 'customers' with search parameters and 'invoice' with route parameters, specifying their schemas using Valibot.
```typescript
// src/shared/navigation.ts
import { createNavigationConfig } from 'next-safe-navigation';
import * as v from 'valibot';
export const { routes, useSafeParams, useSafeSearchParams } =
createNavigationConfig((defineRoute) => ({
customers: defineRoute('/customers', {
search: v.objectWithRest(
{
query: v.optional(v.string(), ''),
page: v.optional(v.pipe(v.string(), v.transform(Number)), 1),
},
v.never(),
),
}),
invoice: defineRoute('/invoices/[invoiceId]', {
params: v.object({
invoiceId: v.string(),
}),
}),
}));
```
--------------------------------
### Navigation Configuration with Zod
Source: https://github.com/lukemorales/next-safe-navigation/blob/main/README.md
Configure navigation routes using `createNavigationConfig` with Zod for schema validation. This example defines routes for 'customers' with search parameters and 'invoice' with route parameters, specifying their schemas using Zod.
```typescript
// src/shared/navigation.ts
import { createNavigationConfig } from 'next-safe-navigation';
import { z } from 'zod';
export const { routes, useSafeParams, useSafeSearchParams } =
createNavigationConfig((defineRoute) => ({
customers: defineRoute('/customers', {
search: z
.object({
query: z.string().default(''),
page: z.coerce.number().default(1),
})
.default({ query: '', page: 1 }),
}),
invoice: defineRoute('/invoices/[invoiceId]', {
params: z.object({
invoiceId: z.string(),
}),
}),
}));
```
--------------------------------
### Define Routes with ArkType Schema
Source: https://github.com/lukemorales/next-safe-navigation/blob/main/README.md
Use ArkType to define schemas for route parameters and search parameters when creating navigation configurations. Ensure ArkType is installed and imported.
```typescript
// src/shared/navigation.ts
import { createNavigationConfig } from 'next-safe-navigation';
import { type } from 'arktype';
export const { routes, useSafeParams, useSafeSearchParams } =
createNavigationConfig((defineRoute) => ({
customers: defineRoute('/customers', {
search: type({
'query?': "string = ''",
'page?': 'string.numeric.parse = 1',
}),
}),
invoice: defineRoute('/invoices/[invoiceId]', {
params: type({
invoiceId: 'string',
}),
}),
}));
```
--------------------------------
### Enable Typed Routes in next.config.js
Source: https://context7.com/lukemorales/next-safe-navigation/llms.txt
Optionally enable typed routes in your next.config.js file to get autocomplete on route paths. This configuration is experimental.
```javascript
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
typedRoutes: true,
},
};
module.exports = nextConfig;
```
--------------------------------
### Define Navigation Configuration
Source: https://context7.com/lukemorales/next-safe-navigation/llms.txt
Use `createNavigationConfig` to define all application routes, including parameters and search schemas. This function returns a typed `routes` map and hooks for client components.
```typescript
import { createNavigationConfig } from 'next-safe-navigation';
import { z } from 'zod';
export const { routes, useSafeParams, useSafeSearchParams } =
createNavigationConfig((defineRoute) => ({
// Simple route — no params, no search
home: defineRoute('/'),
// Route with optional search params (schema uses .default() → optional call-site)
customers: defineRoute('/customers', {
search: z
.object({
query: z.string().default(''),
page: z.coerce.number().default(1),
})
.default({ query: '', page: 1 }),
}),
// Route with required dynamic path param
invoice: defineRoute('/invoices/[invoiceId]', {
params: z.object({
invoiceId: z.string(),
}),
}),
// Route with multiple dynamic params + optional search
organizationUser: defineRoute('/organizations/[orgId]/users/[userId]', {
params: z.object({
orgId: z.string(),
userId: z.string(),
}),
search: z
.object({
q: z.string().optional(),
order: z.enum(['asc', 'desc']).optional(),
})
.optional(),
}),
// Catch-all route
support: defineRoute('/support/[...tickets]', {
params: z.object({
tickets: z.array(z.string()),
}),
}),
// Optional catch-all route
shop: defineRoute('/shop/[[...slug]]', {
params: z.object({
slug: z.array(z.string()).optional(),
}),
}),
}));
```
--------------------------------
### Build URLs with `routes` object
Source: https://context7.com/lukemorales/next-safe-navigation/llms.txt
Use the `routes` object to generate fully-resolved URL strings. Path parameters are required positional arguments, and search schemas accept a `search` key. Arrays in params are joined with `/` for catch-all segments, and search param values are serialized as `URLSearchParams`.
```typescript
import { routes } from '@/shared/navigation';
import Link from 'next/link';
// Simple route — no arguments
routes.home();
// → '/'
// Route with search params (optional because schema has .default())
routes.customers();
// → '/customers'
routes.customers({ search: { query: 'acme', page: 2 } });
// → '/customers?query=acme&page=2'
// Route with a required path param
routes.invoice({ invoiceId: 'inv_123' });
// → '/invoices/inv_123'
// Route with multiple params + optional search
routes.organizationUser({ orgId: 'org_abc', userId: 'usr_xyz' });
// → '/organizations/org_abc/users/usr_xyz'
routes.organizationUser({
orgId: 'org_abc',
userId: 'usr_xyz',
search: { q: 'john', order: 'asc' },
});
// → '/organizations/org_abc/users/usr_xyz?q=john&order=asc'
// Catch-all — array values joined with "/"
routes.support({ tickets: ['billing', 'ticket_99'] });
// → '/support/billing/ticket_99'
// Use directly in JSX
export function Nav() {
return (
);
}
```
--------------------------------
### Runtime Validation in Server Components
Source: https://github.com/lukemorales/next-safe-navigation/blob/main/README.md
Parse search parameters and route parameters in Server Components to ensure runtime validated and accurate type information. This is crucial as schema outputs might differ from inputs due to type coercion.
```typescript
// src/app/customers/page.tsx
import { routes } from "@/shared/navigation";
interface CustomersPageProps {
// ✅ Never assume the types of your params before validation
searchParams?: unknown
}
export default async function CustomersPage({ searchParams }: CustomersPageProps) {
const { query, page } = routes.customers.$parseSearchParams(searchParams);
const customers = await fetchCustomers({ query, page });
return (
)
};
/* --------------------------------- */
// src/app/invoices/[invoiceId]/page.tsx
import { routes } from "@/shared/navigation";
interface InvoicePageProps {
// ✅ Never assume the types of your params before validation
params?: unknown
}
export default async function InvoicePage({ params }: InvoicePageProps) {
const { invoiceId } = routes.invoice.$parseParams(params);
const invoice = await fetchInvoice(invoiceId);
return (
)
};
```
--------------------------------
### URL Builders
Source: https://context7.com/lukemorales/next-safe-navigation/llms.txt
The `routes` object provides callable functions to construct fully-resolved URL strings for your application's routes. It handles path parameters as positional arguments and search parameters through a `search` object.
```APIDOC
## `routes` — URL builders
Each key on the returned `routes` object is a callable function that builds a fully-resolved URL string. For routes with path params the params are required positional arguments. For routes with a `search` schema a `search` key is accepted (required or optional depending on whether the schema itself is optional). Arrays in params are joined with `/` to support catch-all segments. Search param values are serialized as `URLSearchParams`, with array values expanded to repeated keys.
```ts
import { routes } from '@/shared/navigation';
import Link from 'next/link';
// Simple route — no arguments
routes.home();
// → '/'
// Route with search params (optional because schema has .default())
routes.customers();
// → '/customers'
routes.customers({ search: { query: 'acme', page: 2 } });
// → '/customers?query=acme&page=2'
// Route with a required path param
routes.invoice({ invoiceId: 'inv_123' });
// → '/invoices/inv_123'
// Route with multiple params + optional search
routes.organizationUser({ orgId: 'org_abc', userId: 'usr_xyz' });
// → '/organizations/org_abc/users/usr_xyz'
routes.organizationUser({
orgId: 'org_abc',
userId: 'usr_xyz',
search: { q: 'john', order: 'asc' },
});
// → '/organizations/org_abc/users/usr_xyz?q=john&order=asc'
// Catch-all — array values joined with "/"
routes.support({ tickets: ['billing', 'ticket_99'] });
// → '/support/billing/ticket_99'
// Use directly in JSX
export function Nav() {
return (
);
}
```
```
--------------------------------
### Navigation Links with `routes` object
Source: https://github.com/lukemorales/next-safe-navigation/blob/main/README.md
Generate navigation links using the `routes` object provided by `next-safe-navigation`. This ensures type safety and consistency when creating links to different routes within your application.
```typescript
import { routes } from "@/shared/navigation";
export function Header() {
return (
)
};
export function CustomerInvoices({ invoices }) {
return (
{invoices.map(invoice => (
View invoice
))}
)
};
```
--------------------------------
### Runtime Validation in Client Components
Source: https://github.com/lukemorales/next-safe-navigation/blob/main/README.md
Utilize hooks like `useSafeSearchParams` and `useSafeParams` in Client Components for runtime validation of route and search parameters. This ensures type safety when accessing navigation data.
```typescript
// src/app/customers/page.tsx
'use client';
import { useSafeSearchParams } from "@/shared/navigation";
export default function CustomersPage() {
const { query, page } = useSafeSearchParams('customers');
const customers = useSuspenseQuery({
queryKey: ['customers', { query, page }],
queryFn: () => fetchCustomers({ query, page}),
});
return (
)
};
/* --------------------------------- */
// src/app/invoices/[invoiceId]/page.tsx
'use client';
import { useSafeParams } from "@/shared/navigation";
export default function InvoicePage() {
const { invoiceId } = useSafeParams('invoice');
const invoice = useSuspenseQuery({
queryKey: ['invoices', { invoiceId }],
queryFn: () => fetchInvoice(invoiceId),
});
return (
)
};
```
--------------------------------
### Use Safe Params for Route Parameters
Source: https://context7.com/lukemorales/next-safe-navigation/llms.txt
Use `useSafeParams` in Client Components to read and validate route parameters against a schema. TypeScript enforces that only routes with defined `params` schemas can be used. Throws a runtime error if validation fails.
```typescript
// src/app/invoices/[invoiceId]/page.tsx
'use client';
import { useSafeParams } from '@/shared/navigation';
import { useSuspenseQuery } from '@tanstack/react-query';
export default function InvoicePage() {
// Compile error if 'invoice' doesn't have a params schema
// Runtime error with message 'Invalid route params for route "invoice": ...'
const { invoiceId } = useSafeParams('invoice');
// ^? string (inferred from Zod schema output)
const { data: invoice } = useSuspenseQuery({
queryKey: ['invoices', invoiceId],
queryFn: () => fetchInvoice(invoiceId),
});
return ;
}
```
```typescript
// With coercion — orgId comes from URL as string, validated as number
// src/app/organizations/[orgId]/page.tsx
'use client';
import { useSafeParams } from '@/shared/navigation';
export default function OrganizationPage() {
const { orgId } = useSafeParams('organizationUser');
// ^? number (z.coerce.number() transforms the string)
return
Organization: {orgId}
;
}
```
--------------------------------
### Use Safe Search Params for URL Search Parameters
Source: https://context7.com/lukemorales/next-safe-navigation/llms.txt
Utilize `useSafeSearchParams` in Client Components to access and validate URL search parameters against a schema. TypeScript ensures that only routes with defined `search` schemas are accepted. The output type reflects schema transformations and optionality.
```typescript
// src/app/customers/page.tsx
'use client';
import { useSafeSearchParams } from '@/shared/navigation';
import { useSuspenseQuery } from '@tanstack/react-query';
export default function CustomersPage() {
// Compile error if 'customers' has no search schema
const { query, page } = useSafeSearchParams('customers');
// ^? string ^? number (coerced)
const { data: customers } = useSuspenseQuery({
queryKey: ['customers', { query, page }],
queryFn: () => fetchCustomers({ query, page }),
});
return (
);
}
```
```typescript
// Optional schema — return type includes undefined
// src/app/team/page.tsx
'use client';
import { useSafeSearchParams } from '@/shared/navigation';
export default function TeamPage() {
const searchParams = useSafeSearchParams('team');
// ^? { q?: string; order: 'asc' | 'desc' } | undefined
return ;
}
```
--------------------------------
### Parse Search Parameters
Source: https://context7.com/lukemorales/next-safe-navigation/llms.txt
The `$parseSearchParams` method allows parsing and validating raw search parameters for a route within React Server Components. It converts the `searchParams` prop into a structured object according to the route's schema, supporting type coercion.
```APIDOC
## `routes..$parseSearchParams`
Parses and validates raw search params for a route that has a `search` schema. Intended for use in React Server Components. Accepts the raw `searchParams` prop (typed `unknown`), converts it via `URLSearchParams` parsing, then validates against the schema. Supports schema transformations such as `z.coerce.number()` so the output type correctly reflects the converted values.
```ts
// src/app/customers/page.tsx
import { routes } from '@/shared/navigation';
interface CustomersPageProps {
searchParams?: unknown;
}
export default async function CustomersPage({
searchParams,
}: CustomersPageProps) {
// Throws: 'Invalid search params for route "customers": ...' on bad input
const { query, page } = routes.customers.$parseSearchParams(searchParams);
// ^? string ^? number (coerced by z.coerce.number())
const data = await fetchCustomers({ query, page });
return (
);
}
// Route with both params and search
// src/app/organizations/[orgId]/users/page.tsx
interface OrgUsersPageProps {
params?: unknown;
searchParams?: unknown;
}
export default async function OrgUsersPage({
params,
searchParams,
}: OrgUsersPageProps) {
const { orgId } = routes.organizationUser.$parseParams(params);
const { q, order } = routes.organizationUser.$parseSearchParams(searchParams);
const users = await fetchUsers(orgId, { q, order });
return ;
}
```
```
--------------------------------
### Parse Route Parameters
Source: https://context7.com/lukemorales/next-safe-navigation/llms.txt
The `$parseParams` method on a route object is used to parse and validate raw path parameters, typically in React Server Components. It ensures that the provided parameters conform to the route's schema, throwing an error if validation fails.
```APIDOC
## `routes..$parseParams`
Parses and validates raw path params for a route that has a `params` schema. Intended for use in React Server Components where Next.js supplies the raw `params` prop typed as `unknown`. Throws a descriptive error if validation fails, including the route name and the underlying schema error message.
```ts
// src/app/invoices/[invoiceId]/page.tsx
import { routes } from '@/shared/navigation';
interface InvoicePageProps {
// ✅ Always type as unknown — let the library infer the validated output
params?: unknown;
}
export default async function InvoicePage({ params }: InvoicePageProps) {
// Throws: 'Invalid route params for route "invoice": ...' on bad input
const { invoiceId } = routes.invoice.$parseParams(params);
// ^? string (inferred from the Zod schema output)
const invoice = await fetchInvoice(invoiceId);
return ;
}
// Multi-param example
// src/app/organizations/[orgId]/users/[userId]/page.tsx
interface OrgUserPageProps {
params?: unknown;
}
export default async function OrgUserPage({ params }: OrgUserPageProps) {
const { orgId, userId } = routes.organizationUser.$parseParams(params);
// ^? string ^? string
const user = await fetchUser(orgId, userId);
return ;
}
```
```
--------------------------------
### Parse Search Params with `$parseSearchParams`
Source: https://context7.com/lukemorales/next-safe-navigation/llms.txt
Use `$parseSearchParams` in React Server Components to parse and validate raw search parameters against a defined schema. It supports schema transformations like `z.coerce.number()` and throws descriptive errors on validation failure.
```typescript
// src/app/customers/page.tsx
import { routes } from '@/shared/navigation';
interface CustomersPageProps {
searchParams?: unknown;
}
export default async function CustomersPage({
searchParams,
}: CustomersPageProps) {
// Throws: 'Invalid search params for route "customers": ...' on bad input
const { query, page } = routes.customers.$parseSearchParams(searchParams);
// ^? string ^? number (coerced by z.coerce.number())
const data = await fetchCustomers({ query, page });
return (
);
}
```
```typescript
// Route with both params and search
// src/app/organizations/[orgId]/users/page.tsx
interface OrgUsersPageProps {
params?: unknown;
searchParams?: unknown;
}
export default async function OrgUsersPage({
params,
searchParams,
}: OrgUsersPageProps) {
const { orgId } = routes.organizationUser.$parseParams(params);
const { q, order } = routes.organizationUser.$parseSearchParams(searchParams);
const users = await fetchUsers(orgId, { q, order });
return ;
}
```
--------------------------------
### Parse Route Params with `$parseParams`
Source: https://context7.com/lukemorales/next-safe-navigation/llms.txt
Use `$parseParams` in React Server Components to validate raw path parameters against a defined schema. It throws descriptive errors on validation failure, inferring the validated output type from the schema.
```typescript
// src/app/invoices/[invoiceId]/page.tsx
import { routes } from '@/shared/navigation';
interface InvoicePageProps {
// ✅ Always type as unknown — let the library infer the validated output
params?: unknown;
}
export default async function InvoicePage({ params }: InvoicePageProps) {
// Throws: 'Invalid route params for route "invoice": ...' on bad input
const { invoiceId } = routes.invoice.$parseParams(params);
// ^? string (inferred from the Zod schema output)
const invoice = await fetchInvoice(invoiceId);
return ;
}
```
```typescript
// Multi-param example
// src/app/organizations/[orgId]/users/[userId]/page.tsx
interface OrgUserPageProps {
params?: unknown;
}
export default async function OrgUserPage({ params }: OrgUserPageProps) {
const { orgId, userId } = routes.organizationUser.$parseParams(params);
// ^? string ^? string
const user = await fetchUser(orgId, userId);
return ;
}
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.