### 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 ( ) }; ``` -------------------------------- ### 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.