javascript
53 lines · 10 steps
Parsing search params in a Next.js page
A Next.js server component sanitizes URL query params into a typed filter object before querying products.
Explained by
highlit
1import { notFound } from 'next/navigation';
2
3const PER_PAGE = 24;
4const SORT_OPTIONS = ['relevance', 'price-asc', 'price-desc', 'newest'];
5
6function parseFilters(searchParams) {
7 const q = typeof searchParams.q === 'string' ? searchParams.q.trim() : '';
8
9 const sort = SORT_OPTIONS.includes(searchParams.sort)
10 ? searchParams.sort
11 : 'relevance';
12
13 const page = Math.max(1, Number.parseInt(searchParams.page, 10) || 1);
14
15 const min = Number.parseFloat(searchParams.min);
16 const max = Number.parseFloat(searchParams.max);
17 const minPrice = Number.isFinite(min) && min >= 0 ? min : null;
18 const maxPrice = Number.isFinite(max) && max >= 0 ? max : null;
19
20 const categories = []
21 .concat(searchParams.category ?? [])
22 .filter((c) => typeof c === 'string' && c.length > 0);
23
24 const inStock = searchParams.inStock === 'true';
25
26 return { q, sort, page, minPrice, maxPrice, categories, inStock };
27}
28
29export default async function ProductsPage({ searchParams }) {
30 const filters = parseFilters(await searchParams);
31
32 if (filters.minPrice !== null && filters.maxPrice !== null && filters.minPrice > filters.maxPrice) {
33 notFound();
34 }
35
36 const { products, total } = await searchProducts({
37 ...filters,
38 limit: PER_PAGE,
39 offset: (filters.page - 1) * PER_PAGE,
40 });
41
42 if (filters.page > 1 && products.length === 0) {
43 notFound();
44 }
45
46 return (
47 <ProductGrid
48 products={products}
49 filters={filters}
50 totalPages={Math.ceil(total / PER_PAGE)}
51 />
52 );
53}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1User-supplied query params are untrusted strings, so coerce and bound each one before using it.
- 2Centralizing parsing in one function gives every downstream consumer a clean, predictable filter shape.
- 3Returning notFound() for impossible or empty states keeps invalid URLs from rendering broken pages.
Related explainers
javascript
'use server' import { revalidatePath } from 'next/cache' import { redirect } from 'next/navigation'
How a Next.js Server Action updates a post
server-actions
authorization
validation
Intermediate
7 steps
javascript
const express = require('express'); const v1 = express.Router();
Versioning an API with Express Routers
api versioning
routing
modularity
Intermediate
10 steps
python
import csv import io from datetime import datetime
Streaming a CSV export in Flask
streaming
generators
csv
Intermediate
9 steps
php
<?php class ImageUploadService {
Validating file uploads safely in PHP
file-upload
input-validation
security
Intermediate
8 steps
javascript
const RATE_LIMIT = 100; const WINDOW_MS = 60 * 1000; const BLOCK_MS = 5 * 60 * 1000;
Building a rate-limiting middleware in Express
rate-limiting
middleware
closures
Intermediate
9 steps
php
<?php namespace App\View;
Building a safe HTML escaper in PHP
security
xss
escaping
Intermediate
6 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/parsing-search-params-in-a-next-js-page-explained-javascript-20a1/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.