Design a Search Results Page
System design for a search results page: filters, sorting, facets, infinite scroll vs pagination, and performance at scale.
A search results page is a core pattern in e-commerce, content sites, and dashboards. It combines query input, result list, filters, sorting, and often facets. Here's how to structure your answer in an interview and what trade-offs to call out.
Requirements Clarification
Functional: Display results for a query; support filters (category, price range, etc.) and sort options (relevance, date, price); show facets or filter counts; load more via pagination or infinite scroll. Non-functional: Fast first result (e.g. < 1.5s), SEO-friendly URLs for key filters, accessible filters and result list.
Clarify with the interviewer: Is this for e-commerce (product cards, price filters) or content (articles, date/relevance)? Do we need real-time inventory or availability? Are facets dynamic (computed from current result set) or static categories? Answers will shape the API and state model.
High-Level Architecture
SearchPage contains: SearchInput (debounced), FilterSidebar (facets, applied filters), SortDropdown, ResultList (virtualized if large), and Pagination or infinite scroll sentinel. State: query, filters, sort, page/cursor; sync with URL (query params) for shareability and SEO.
State and URL: Keep the URL as the source of truth for query, filters, and sort so that refreshing or sharing the link preserves the view. Parse query params on load and when the user uses browser back/forward. Update the URL when the user changes search or filters (replaceState or pushState) so the history stack stays meaningful.
API Design
GET /search?q=...&filters=...&sort=...&page=... or cursor-based. Response: results array, total count (or approximate), facet counts per filter. Use debouncing (e.g. 300ms) on query input; consider prefetching or caching popular queries.
Cursor vs offset: For large or changing result sets, cursor-based pagination is more stable than offset (no skipped or duplicated items when new results are added). Return a nextCursor in the response; send it back for the next page. For approximate total count, the API might return "10,000+" instead of an exact number to avoid expensive counts. Facet counts can be approximate for the same reason.
Filters and Facets
Facets are the distinct values and counts per filter dimension (e.g. "Category: Electronics (120), Books (80)"). Backend returns them with the result set. Frontend applies selected filters to the next request; show applied filters as chips with clear action. Avoid filter combinations that return zero results—either disable or show "no results" with clear CTA to reset.
UX details: When the user selects a filter, update the URL and refetch. Disable facet values that would yield zero results (or show them grayed with "0") so users don't dead-end. Allow multiple values per dimension (e.g. Category: Electronics OR Books) unless the product explicitly requires single-select. Clear-all and per-chip remove should be obvious and keyboard-accessible.
Pagination vs Infinite Scroll
Pagination is better for SEO, deep linking, and keyboard users. Infinite scroll is better for mobile and discovery. Hybrid: "Load more" button that appends results. Preserve scroll position when navigating back. For very long sessions, consider virtualizing the list.
Trade-offs: Infinite scroll can hurt accessibility (focus and "back to top") and make it hard to reach the footer. A "Load more" button keeps a single tab stop and gives the user control. If you do infinite scroll, ensure there's a way to jump to the top and that screen readers can navigate the growing list. For SEO, server-render the first page of results and ensure critical content is in the initial HTML.
Performance and Accessibility
Virtualize long lists; lazy-load images in results. Ensure focus management when filters change and results update. Use semantic list and headings; announce result count to screen readers. Loading and empty states must be clear and accessible.
Virtualization: If the result list can have hundreds of items, use a virtualized list (e.g. only render visible rows plus a small buffer) so the DOM stays small. Images in result cards should use lazy loading (loading="lazy" or Intersection Observer) and explicit dimensions to avoid layout shift. When filters or sort change, move focus to the result list or announce the new count so keyboard and screen-reader users know the content updated.
Edge Cases
Handle empty query (show trending or recent, or a prompt to type); no results (clear message and suggest removing filters or trying different terms); and API errors (retry button, fallback UI). For slow networks, show skeleton cards or a loading state and avoid blocking the whole page. Consider request cancellation when the user changes the query or filters before the previous request completes.
A well-designed search results page balances power (filters, sort) with simplicity, keeps URL in sync, and stays fast and accessible. Test with real query volumes and slow networks to validate performance and error handling.
Analytics and Tuning
Track which results get clicked, which filters are used, and where users drop off. Use that data to tune ranking, default sort, and facet order. A/B test layout and result density to improve conversion. Log slow queries and empty results so you can improve the backend and UX over time.
Related articles
- System DesignDesign Autocomplete / Typeahead Search
System design for building a Google-like autocomplete search component: debouncing, caching, keyboard navigation, race conditions, and mobile considerations.
Read article - System DesignDesign a Comments Thread
System design for nested comments: replies, pagination, real-time updates, and moderation. Frontend architecture and data shape.
Read article - System DesignDesign a Social Media News Feed
System design for a Twitter/Facebook-style news feed: infinite scroll, virtualization, optimistic updates, real-time updates, lazy loading, and content ranking.
Read article - System DesignDesign a Real-Time Chat Application
System design for Slack/WhatsApp-style chat: WebSocket management, message ordering, offline support, typing indicators, read receipts, search, and file uploads.
Read article