# How to Handle Route Parameters in OmniRoute: Dynamic Routing with Next.js App Router

> Learn to handle route parameters in OmniRoute using Next.js App Router dynamic segments. Extract and validate URL parameters with Zod for robust dynamic routing. Optimize your Next.js app today.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-08-17

---

**OmniRoute handles route parameters using Next.js 16 App Router dynamic segments, extracting values from URL paths via the `params` property and validating them with Zod schemas before delegating to core handlers in `open-sse/handlers/`.**

The OmniRoute API gateway is built on the Next.js 16 App Router file-system convention. Dynamic URL segments map directly to folder names, creating a type-safe bridge between incoming requests and provider-specific business logic. Understanding how to extract, validate, and process these parameters is essential for extending the platform or debugging provider integrations.

## Dynamic Segment Syntax in Next.js App Router

OmniRoute follows Next.js App Router conventions for dynamic routing. Single brackets capture specific path segments, while double brackets create optional catch-all patterns.

- **[param]** – Captures a single path segment as a named parameter (e.g., `[provider]` becomes `params.provider`).
- **[[...slug]]** – Captures zero or more path segments as an array, useful for variable-length identifiers like model paths or combo tokens.

In `src/app/api/v1/providers/[provider]/models/route.ts`, the `[provider]` directory captures provider names such as `openai` or `anthropic`. For routes requiring flexible path depths, such as `src/app/api/v1/vscode/combos/[token]/[[...slug]]/route.ts`, the double-bracket syntax stores remaining segments as `params.slug`.

## Extracting Route Parameters from the Request Context

Route handlers in OmniRoute receive parameters through the second argument of the route function, typed explicitly for safety.

```typescript
// src/app/api/v1/providers/[provider]/models/route.ts
import { NextRequest } from 'next/server';

export async function GET(
  req: NextRequest,
  { params }: { params: { provider: string } }
) {
  const { provider } = params;  // "openai", "anthropic", etc.
  // ... handler logic
}

```

The `params` object contains key-value pairs where keys match the bracket names in the file path. For catch-all routes, the value is a string array:

```typescript
// src/app/api/v1/vscode/combos/[token]/[[...slug]]/route.ts
export async function POST(
  req: NextRequest,
  { params }: { params: { token: string; slug?: string[] } }
) {
  const token = params.token;
  const comboPath = (params.slug ?? []).join('/');  // e.g., "gpt-4o/preview"
}

```

## Validating Parameters with Zod Schemas

OmniRoute enforces strict input validation using Zod schemas before any business logic executes. Validation typically occurs in the same folder as the route or via shared helpers like [`src/app/api/v1/_helpers/apiKeyScope.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/_helpers/apiKeyScope.ts).

**Single parameter validation:**

```typescript
import { z } from 'zod';

const ProviderSchema = z.enum(['openai', 'anthropic', 'gemini']);
const provider = ProviderSchema.parse(params.provider);

```

**Complex parameter validation:**

```typescript
const TokenSchema = z.string().uuid();
const token = TokenSchema.parse(params.token);

```

This pattern guarantees that only well-formed values reach the core handlers, preventing malformed provider names or invalid tokens from propagating through the system.

## Handling Catch-All and Optional Catch-All Segments

Variable-length routes handle model identifiers or combo paths that may contain slashes. The `[[...slug]]` convention stores segments as an array, allowing reconstruction of the original path.

```typescript
// src/app/api/v1/vscode/combos/[token]/[[...slug]]/route.ts
const modelPath = params.slug?.join('/') ?? '';

```

This approach supports endpoints where the identifier itself contains multiple segments, such as `gpt-4o/preview` or custom combo configurations, without requiring rigid URL structures.

## Routing Pipeline: From Extraction to Execution

After parameter extraction and validation, OmniRoute follows a standardized pipeline:

1. **CORS pre-flight handling** – Managed at the route edge.
2. **Parameter validation** – Zod schemas verify `params` and request body.
3. **Feature flag checks** – Gates like PII redaction consult [`src/shared/constants/featureFlagDefinitions.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/featureFlagDefinitions.ts).
4. **Handler delegation** – Validated parameters pass to core functions in `open-sse/handlers/`, such as `handleChatCore` or `handleEmbedding`.

The API route files act as thin wrappers. For example, [`src/app/api/v1/relay/chat/completions/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/relay/chat/completions/route.ts) extracts parameters, validates them, then delegates to the central routing service in [`src/open-sse/services/combo.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/open-sse/services/combo.ts) for provider selection and circuit-breaker checks.

## Summary

- OmniRoute uses Next.js 16 App Router file-system routing with `[param]` and `[[...slug]]` conventions.
- Parameters extract via the `params` property in the request context, typed explicitly for TypeScript safety.
- Zod schemas validate all dynamic segments before business logic executes, typically defined in `*_schema.ts` files or shared helpers.
- Catch-all segments `[[...slug]]` capture variable-length paths as arrays, reconstructing identifiers like model paths.
- Validated requests delegate from route files to core handlers in `open-sse/handlers/` after CORS handling and feature flag checks.

## Frequently Asked Questions

### What format does OmniRoute use for dynamic route parameters?

OmniRoute uses Next.js 16 App Router bracket notation. Single brackets like `[provider]` capture individual path segments, while double brackets like `[[...slug]]` create optional catch-all patterns that capture multiple segments into an array. These map directly to the file system under `src/app/api/v1/`.

### How does OmniRoute validate route parameters?

All dynamic values undergo validation using Zod schemas. The route handler calls parse methods on schemas defined locally or imported from shared locations like [`src/app/api/v1/_helpers/apiKeyScope.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/_helpers/apiKeyScope.ts). This ensures type safety and prevents invalid provider names or malformed tokens from reaching downstream services.

### What is the difference between `[param]` and `[...slug]` in OmniRoute?

The `[param]` syntax captures exactly one path segment as a string value (e.g., `params.provider`). The `[[...slug]]` syntax (double brackets) captures zero or more segments as a string array, allowing reconstruction of multi-part identifiers. OmniRoute uses single brackets for fixed entities like providers and double brackets for variable model paths or combo identifiers.

### Where does the actual business logic execute after parameter extraction?

After validation, API routes delegate to centralized handlers located in `open-sse/handlers/`. Files like [`src/app/api/v1/relay/chat/completions/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/relay/chat/completions/route.ts) serve as thin wrappers that validate inputs, check feature flags against [`src/shared/constants/featureFlagDefinitions.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/featureFlagDefinitions.ts), then call core services such as [`src/open-sse/services/combo.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/open-sse/services/combo.ts) to execute provider selection and request routing.