Skip to content

Retrieving Query Parameters in Next.js Server Components

Problem Statement

Next.js 13 introduced the app directory architecture where components are server components by default. While server components provide direct access to features like cookies() and headers(), there's no built-in method to access URL query parameters like ?name=value in arbitrary server components. This creates challenges when you need to react to dynamic URL parameters without traditional approaches like getServerSideProps.

1. Accessing Query Parameters in Page Components

Page components (page.tsx) receive query parameters via the searchParams prop:

tsx
export default function Page({
  searchParams,
}: {
  searchParams?: { [key: string]: string | string[] | undefined };
}) {
  const filter = searchParams?.filter || 'default'; // Access ?filter=value
  const sort = searchParams?.sort || 'asc';         // Access ?sort=value
  
  return <div>Filter: {filter}, Sort: {sort}</div>;
}

Notes:

  • This is the standard approach for page components
  • Works similarly in layout.tsx and template.tsx
  • Automatically handles both static and dynamic routes

2. Using URLSearchParams API in Route Handlers

For API routes (route.ts), parse query parameters using the browser's native URL and URLSearchParams:

ts
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const query = searchParams.get('q');
  const page = searchParams.get('page') || '1';

  // Return results based on query paramters
  return Response.json({ results: [] });
}

3. Sharing Query Parameters via Middleware

Access query parameters in any server component by propagating URL information through request headers:

ts
import { NextRequest, NextResponse } from 'next/server';

export function middleware(request: NextRequest) {
  const requestHeaders = new Headers(request.headers);
  requestHeaders.set('x-url', request.url);
  
  return NextResponse.next({
    request: { headers: requestHeaders }
  });
}

Then in any server component:

tsx
import { headers } from 'next/headers';

export default function Component() {
  const url = headers().get('x-url') || '';
  const searchParams = new URL(url).searchParams;
  
  const theme = searchParams.get('theme'); // Access ?theme=value
  // ...
}

Alternative Approaches

Type-Safe Query Parameters with NUQS

For complex query parameter handling in server components:

tsx
import { parseAsString, createSearchParamsCache } from 'nuqs/server';

const cache = createSearchParamsCache({
  theme: parseAsString.withDefault('light'),
  pageIndex: parseAsString.withDefault('0')
});

export default function Page({ searchParams }) {
  const { theme, pageIndex } = cache.parse(searchParams);
  
  return <div>Theme: {theme}, Page: {pageIndex}</div>;
}

Third-Party Consideration

While NUQS provides type safety and parsing utilities, evaluate whether your use case justifies adding external dependencies.

Parsing Query Parameters Manually

Utility functions for custom parsing logic:

ts
export function parseQuery(url: string) {
  const searchParams = new URLSearchParams(new URL(url).search);
  return Object.fromEntries(searchParams.entries());
}

// Usage in server components
const query = parseQuery(headers().get('x-url') || '');

When to Use

  • Requires custom query parameter handling
  • Works across both server and client components

Key Implementation Details

  1. Component Hierarchy Considerations
    • Only pass searchParams to client components as needed
    • Avoid deeply nested propagation when possible
tsx
// Pass only necessary values to client components
<ClientComponent filter={searchParams?.filter} />
  1. Edge Cases
    • Handle array parameters: ?ids=1&ids=2
    • Manage encoding/decoding
    • Consider URL length limits
tsx
// Handling array parameters
const ids = searchParams.id 
  ? Array.isArray(searchParams.id)
    ? searchParams.id 
    : [searchParams.id]
  : [];

Conclusion

While Next.js provides direct searchParams access in page/layout components, other server components require either:

  1. Middleware propagation via headers
  2. Parameter passing through props
  3. Third-party libraries like NUQS

For API routes, use the native URL API for reliable parameter parsing. The optimal approach depends on whether you're working with page components, API handlers, or generic server components.

Version Compatibility

These solutions apply to Next.js 13+ and leverage features available as of Next.js 15. Verify compatibility with your project's specific version.