<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged pagination</title>
<link>https://coderlegion.com/tag/pagination</link>
<description>Powered by Question2Answer</description>
<item>
<title>Faceted Navigation and Pagination for Ecommerce SEO</title>
<link>https://coderlegion.com/25631/faceted-navigation-and-pagination-for-ecommerce-seo</link>
<description>
&lt;p class=&quot;article-intro&quot;&gt;&lt;strong&gt;Direct answer:&lt;/strong&gt; Treat each filter and page-number URL as a product-discovery decision, not as a by-product of the interface. Keep crawlable links to categories, useful curated facets, and paginated product sets. Block or otherwise contain combinations that add no search value. Return a real &lt;code&gt;404&lt;/code&gt; for empty or nonsensical combinations, and use consistent canonicals, internal links, and sitemap policy for every indexable route.&lt;/p&gt;

      &lt;h2 id=&quot;decide-which-url-families-deserve-crawl&quot;&gt;1. Decide which URL families deserve crawling&lt;/h2&gt;
      &lt;p&gt;Start with an inventory of URL-generating controls: category paths, attributes, price bands, sort orders, pagination, search, tracking, session state, display modes, and campaign parameters. Record the parameter order, possible values, combinations, status behavior, canonical target, internal links, and intended search job.&lt;/p&gt;
      &lt;p&gt;The objective is not to make every filtered result indexable. It is to make important inventory discoverable while keeping low-value combinations from consuming server and crawl resources. A filtered page can earn a place in search when it represents a stable demand, has enough useful inventory, has distinct context, and can be maintained as a real landing page.&lt;/p&gt;
      &lt;div class=&quot;article-table-wrap&quot;&gt;&lt;table class=&quot;article-table article-table-wide&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;URL family&lt;/th&gt;&lt;th&gt;Default policy&lt;/th&gt;&lt;th&gt;Keep it crawlable when&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
        &lt;tr&gt;&lt;td&gt;Category or curated collection&lt;/td&gt;&lt;td&gt;Indexable, self-canonical&lt;/td&gt;&lt;td&gt;It has a clear scope, useful inventory, and durable internal links&lt;/td&gt;&lt;/tr&gt;
        &lt;tr&gt;&lt;td&gt;Single useful facet&lt;/td&gt;&lt;td&gt;Evaluate deliberately&lt;/td&gt;&lt;td&gt;Demand, inventory, copy, links, and ownership justify a landing page&lt;/td&gt;&lt;/tr&gt;
        &lt;tr&gt;&lt;td&gt;Sort, tracking, or session state&lt;/td&gt;&lt;td&gt;Contain or exclude&lt;/td&gt;&lt;td&gt;Almost never creates a separate search task&lt;/td&gt;&lt;/tr&gt;
        &lt;tr&gt;&lt;td&gt;Pagination&lt;/td&gt;&lt;td&gt;Crawlable sequence&lt;/td&gt;&lt;td&gt;Later pages contain products that are not otherwise reachable&lt;/td&gt;&lt;/tr&gt;
        &lt;tr&gt;&lt;td&gt;Empty or impossible combination&lt;/td&gt;&lt;td&gt;Return 404&lt;/td&gt;&lt;td&gt;There is no matching inventory or valid URL state&lt;/td&gt;&lt;/tr&gt;
      &lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
      &lt;h3&gt;Example policy for a shoe catalog&lt;/h3&gt;
      &lt;div class=&quot;article-table-wrap&quot;&gt;&lt;table class=&quot;article-table article-table-wide&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Example URL&lt;/th&gt;&lt;th&gt;Policy&lt;/th&gt;&lt;th&gt;Why&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
        &lt;tr&gt;&lt;td&gt;&lt;code&gt;/shoes/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Indexable&lt;/td&gt;&lt;td&gt;Primary category page&lt;/td&gt;&lt;/tr&gt;
        &lt;tr&gt;&lt;td&gt;&lt;code&gt;/shoes/black/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Curated and indexable&lt;/td&gt;&lt;td&gt;Stable facet with useful inventory, context, and internal links&lt;/td&gt;&lt;/tr&gt;
        &lt;tr&gt;&lt;td&gt;&lt;code&gt;/shoes/?sort=price&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Non-indexable&lt;/td&gt;&lt;td&gt;The sort order does not create a separate search destination&lt;/td&gt;&lt;/tr&gt;
        &lt;tr&gt;&lt;td&gt;&lt;code&gt;/shoes/?color=black&amp;amp;size=42&amp;amp;page=3&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Depends on the approved facet policy&lt;/td&gt;&lt;td&gt;Keep page 3 crawlable only when the underlying facet is an approved destination&lt;/td&gt;&lt;/tr&gt;
        &lt;tr&gt;&lt;td&gt;&lt;code&gt;/shoes/?color=purple&amp;amp;material=banana&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Return 404&lt;/td&gt;&lt;td&gt;The combination has no valid results or meaningful catalog state&lt;/td&gt;&lt;/tr&gt;
      &lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

      &lt;h2 id=&quot;model-the-filter-space-before-changing-robots&quot;&gt;2. Model the filter space before changing robots.txt&lt;/h2&gt;
      &lt;p&gt;Sample the combinations a shopper and a crawler can create. Count the number of values per parameter, test parameter order, and estimate how many URLs appear after two, three, or more filters are combined. Include combinations produced by links, forms, JavaScript state, feeds, and old URLs.&lt;/p&gt;
      &lt;p&gt;Google's &lt;a href=&quot;https://developers.google.com/crawling/docs/faceted-navigation&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;faceted navigation guidance&lt;/a&gt; explains that parameter-based filters can create an effectively infinite URL space. If filtered URLs do not need to appear in Google, a robots policy can prevent crawling of known parameter families. URL fragments can also represent purely client-side filters because Google generally does not use fragments for crawling and indexing. Neither approach should be used to hide products that have no other crawlable discovery path.&lt;/p&gt;
      &lt;div class=&quot;article-callout&quot;&gt;&lt;p&gt;&lt;strong&gt;Make the policy enforceable.&lt;/strong&gt; A written rule such as &amp;ldquo;filters are not indexable&amp;rdquo; is not enough. Test every navigation component and template that can emit the URL. One unfiltered link, feed, or canonical mismatch can reopen the crawl path.&lt;/p&gt;&lt;/div&gt;
      &lt;p&gt;Do not use &lt;code&gt;rel=&quot;nofollow&quot;&lt;/code&gt; as the only control for a large parameter space. If the business needs a filtered page in search, design that route as a maintained landing page instead of treating a random combination as an SEO asset.&lt;/p&gt;

      &lt;h2 id=&quot;build-stable-filtered-landing-pages&quot;&gt;3. Build stable filtered landing pages only for real search jobs&lt;/h2&gt;
      &lt;p&gt;For every approved facet, choose one URL representation and keep its logical filter order stable. Use the standard &lt;code&gt;&amp;amp;&lt;/code&gt; separator for query parameters. If filters are encoded in path segments, reject duplicate filters and keep the sequence deterministic. Link to the same preferred URL from navigation, related collections, feeds, and sitemaps.&lt;/p&gt;
      &lt;p&gt;A useful filtered landing page needs more than a parameter and a changed product grid. Give it a descriptive title and heading, explain the selected scope, show meaningful inventory, expose links to the parent category and relevant products, and define what happens when stock changes. Assign an owner who can remove or merge the page when demand or inventory disappears.&lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;Use one stable URL for one stable filter combination.&lt;/li&gt;
        &lt;li&gt;Keep the selected state visible in HTML, not only in client-side state.&lt;/li&gt;
        &lt;li&gt;Give the page enough context to stand on its own.&lt;/li&gt;
        &lt;li&gt;Prevent sort, tracking, session, and display parameters from creating competing variants.&lt;/li&gt;
        &lt;li&gt;Return &lt;code&gt;404&lt;/code&gt; for no-result, duplicate, or nonsensical combinations.&lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;Canonical tags can consolidate duplicate signals, but they do not replace a crawl policy. Google describes canonicals as a preference that can be overridden, while redirects, canonical annotations, and sitemap inclusion work best when they all identify the same preferred URL. Use the &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/guides/fix-sitemap-redirects-non-canonical-urls&quot;&gt;sitemap and non-canonical URL guide&lt;/a&gt; when those signals disagree.&lt;/p&gt;

      &lt;h2 id=&quot;make-pagination-a-crawlable-sequence&quot;&gt;4. Make pagination a crawlable sequence&lt;/h2&gt;
      &lt;p&gt;Pagination should expose distinct URLs for distinct result pages and link them sequentially with normal &lt;code&gt;&amp;lt;a href&amp;gt;&lt;/code&gt; elements. Test the first, middle, and final page of each important collection. Verify status, canonical, title, heading, product links, empty state, and what happens when products are added or removed.&lt;/p&gt;
      &lt;p&gt;Google's &lt;a href=&quot;https://developers.google.com/search/docs/specialty/ecommerce/pagination-and-incremental-page-loading&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;pagination documentation&lt;/a&gt; notes that crawlers generally find URLs in link &lt;code&gt;href&lt;/code&gt; attributes. They do not reliably click a Load more button or trigger the user action that powers infinite scroll. A JavaScript interface can still be useful, but it needs an underlying URL sequence or another crawlable discovery route.&lt;/p&gt;
      &lt;div class=&quot;article-table-wrap&quot;&gt;&lt;table class=&quot;article-table&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pattern&lt;/th&gt;&lt;th&gt;SEO implementation test&lt;/th&gt;&lt;th&gt;Common failure&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
        &lt;tr&gt;&lt;td&gt;Page numbers&lt;/td&gt;&lt;td&gt;Each page has a stable URL and links to the next available page&lt;/td&gt;&lt;td&gt;Only page one is linked in source HTML&lt;/td&gt;&lt;/tr&gt;
        &lt;tr&gt;&lt;td&gt;Load more&lt;/td&gt;&lt;td&gt;Each incremental state has a retrievable URL or all important items have another path&lt;/td&gt;&lt;td&gt;Products exist only after a click that crawlers do not perform&lt;/td&gt;&lt;/tr&gt;
        &lt;tr&gt;&lt;td&gt;Infinite scroll&lt;/td&gt;&lt;td&gt;Scrolling states map to crawlable URLs and do not require interaction for discovery&lt;/td&gt;&lt;td&gt;One URL hides a long catalog behind browser events&lt;/td&gt;&lt;/tr&gt;
        &lt;tr&gt;&lt;td&gt;Empty final page&lt;/td&gt;&lt;td&gt;Removed page numbers return the correct state and do not loop&lt;/td&gt;&lt;td&gt;Redirects send every stale page to an unrelated category&lt;/td&gt;&lt;/tr&gt;
      &lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
      &lt;p&gt;Do not canonicalize every later page to page one when those pages contain distinct products. Do not submit every page-number URL to the sitemap automatically either. The sitemap should reinforce the store's intended indexable inventory, while internal pagination links keep products discoverable.&lt;/p&gt;

      &lt;h2 id=&quot;separate-filtering-from-pagination&quot;&gt;5. Separate filtering, sorting, and pagination signals&lt;/h2&gt;
      &lt;p&gt;Inspect combined states such as &lt;code&gt;?color=green&amp;amp;sort=price&amp;amp;page=3&lt;/code&gt;. Decide whether the page number belongs to the selected collection, whether sorting changes the search job, and which parameters should be removed from internal links and canonicals. The same product should not be described through a dozen competing URL patterns because different controls append parameters in different orders.&lt;/p&gt;
      &lt;p&gt;Use a small representative matrix:&lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;unfiltered category, first page;&lt;/li&gt;
        &lt;li&gt;approved single facet, first and later pages;&lt;/li&gt;
        &lt;li&gt;two filters with a valid result set;&lt;/li&gt;
        &lt;li&gt;sort-only and tracking-only variants;&lt;/li&gt;
        &lt;li&gt;an empty combination and a malformed combination;&lt;/li&gt;
        &lt;li&gt;a product reachable only from a deep page.&lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;Compare requested URL, final URL, status, canonical, robots directives, source links, rendered links, sitemap presence, and Search Console evidence. A crawl such as the one described in the &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/guides/ecommerce-seo-audit-checklist&quot;&gt;ecommerce SEO audit checklist&lt;/a&gt; helps establish the sitewide inventory; this guide focuses on the filter and pagination behavior behind that inventory.&lt;/p&gt;

      &lt;h2 id=&quot;validate-empty-states-and-catalog-drift&quot;&gt;6. Validate empty states and catalog drift&lt;/h2&gt;
      &lt;p&gt;Products change faster than URL policies. A combination that was useful last season can become empty after inventory or taxonomy changes. Test the empty state at the application and HTTP levels. Google recommends a proper &lt;code&gt;404&lt;/code&gt; for combinations with no results, duplicate filters, nonsensical paths, and nonexistent pagination URLs rather than redirecting every case to a generic error or category page.&lt;/p&gt;
      &lt;p&gt;If the URL represents a durable curated collection whose products are temporarily unavailable, it may remain live with a &lt;code&gt;200&lt;/code&gt; response only when it still provides useful collection context and relevant alternatives. A dynamically generated filter combination with no valid results should return &lt;code&gt;404&lt;/code&gt;. Record the distinction by template, and do not allow a thin error message with a successful status to become a soft 404.&lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;Re-run the sample after category, attribute, or inventory imports.&lt;/li&gt;
        &lt;li&gt;Watch for duplicate parameter order and duplicate path segments.&lt;/li&gt;
        &lt;li&gt;Check that stale pagination links disappear or resolve predictably.&lt;/li&gt;
        &lt;li&gt;Keep replacement links relevant when a curated facet is retired.&lt;/li&gt;
        &lt;li&gt;Compare sitemap and internal-link sets after major catalog changes.&lt;/li&gt;
      &lt;/ul&gt;

      &lt;h2 id=&quot;release-and-monitor-the-url-policy&quot;&gt;7. Release and monitor the URL policy&lt;/h2&gt;
      &lt;p&gt;Release one parameter family or template at a time. Keep a before-and-after crawl sample, a list of URL patterns, and the expected response for each class. Check server logs, crawl reports, Search Console indexing signals, sitemap errors, and product discovery after deployment. A drop in crawled URLs is not automatically a problem if low-value combinations were removed. A drop in product discovery is.&lt;/p&gt;
      &lt;p&gt;Prioritize defects by template reach and user impact:&lt;/p&gt;
      &lt;ol&gt;
        &lt;li&gt;Restore crawlable discovery for products with no other internal path.&lt;/li&gt;
        &lt;li&gt;Stop high-volume parameter families that create duplicates or empty pages.&lt;/li&gt;
        &lt;li&gt;Repair conflicting redirects, canonicals, links, and sitemaps.&lt;/li&gt;
        &lt;li&gt;Fix pagination states that hide later inventory.&lt;/li&gt;
        &lt;li&gt;Review curated facets for unique context, useful inventory, and ownership.&lt;/li&gt;
      &lt;/ol&gt;
      &lt;p&gt;For a broader technical review, combine this page with the &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/guides/technical-seo-audit-screaming-frog-search-console&quot;&gt;technical crawl and Search Console workflow&lt;/a&gt;. For product template decisions, continue with &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/guides/product-category-page-seo&quot;&gt;Product and Category Page SEO&lt;/a&gt;.&lt;/p&gt;

      &lt;h2 id=&quot;what-not-to-do&quot;&gt;What not to do&lt;/h2&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;strong&gt;Do not index every filter combination.&lt;/strong&gt; Most combinations are interface states, not durable search destinations.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Do not block the only path to products.&lt;/strong&gt; Contain low-value facets while preserving crawlable category and product discovery.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Do not use canonical as a crawl-budget switch.&lt;/strong&gt; It is a consolidation signal, not a substitute for URL controls.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Do not redirect empty combinations to the parent category by default.&lt;/strong&gt; Return the correct 404 state when no valid inventory exists.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Do not hide pagination behind a click-only interface.&lt;/strong&gt; Expose links or another durable discovery path.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Do not mix parameter order across templates.&lt;/strong&gt; Stable URL construction makes monitoring and consolidation possible.&lt;/li&gt;
      &lt;/ul&gt;

      &lt;h2 id=&quot;verification-checklist&quot;&gt;Verification checklist&lt;/h2&gt;
      &lt;ul&gt;
        &lt;li&gt;Every filter family has a documented crawl and index policy.&lt;/li&gt;
        &lt;li&gt;Approved facets use stable URLs, useful context, meaningful inventory, and a responsible owner.&lt;/li&gt;
        &lt;li&gt;Sort, tracking, session, and display parameters do not create uncontrolled competing URLs.&lt;/li&gt;
        &lt;li&gt;Pagination uses stable page URLs and crawlable sequential links.&lt;/li&gt;
        &lt;li&gt;Products on later pages are reachable through crawlable pagination links or another durable internal discovery path.&lt;/li&gt;
        &lt;li&gt;Empty, duplicate, malformed, and nonexistent pagination URLs return the intended status.&lt;/li&gt;
        &lt;li&gt;Internal links, canonicals, redirects, feeds, and sitemaps agree on preferred URLs.&lt;/li&gt;
        &lt;li&gt;Representative desktop and mobile states expose the same selected filters and product links.&lt;/li&gt;
        &lt;li&gt;A post-release crawl and Search Console review detect drift after catalog changes.&lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;Faceted navigation and pagination are working when the store can explain which URL classes help shoppers and search discovery, which classes are contained, how later products are reached, and what happens when inventory changes.&lt;/p&gt;

      &lt;h2 id=&quot;evidence-basis&quot;&gt;Evidence basis&lt;/h2&gt;
      &lt;p&gt;Google's faceted navigation, pagination, and canonicalization guidance were checked from official documentation on August 25, 2026. The URL-class matrix, release sequence, monitoring priorities, and ownership model are FloxoLab implementation frameworks, not Google ranking factors or guarantees.&lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;a href=&quot;https://developers.google.com/crawling/docs/faceted-navigation&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Google for Developers: managing crawling of faceted navigation URLs&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;https://developers.google.com/search/docs/specialty/ecommerce/pagination-and-incremental-page-loading&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Google Search Central: pagination and incremental page loading&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Google Search Central: specify a canonical with rel=canonical&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;

      &lt;nav class=&quot;article-related&quot; aria-label=&quot;Related reading&quot;&gt;&lt;p class=&quot;article-related-h mono&quot;&gt;Continue the ecommerce SEO sequence&lt;/p&gt;&lt;ul&gt;
        &lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/guides/ecommerce-seo-audit-checklist&quot;&gt;Scope the ecommerce URL and template audit&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/guides/product-category-page-seo&quot;&gt;Build useful product and category templates&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/guides/fix-sitemap-redirects-non-canonical-urls&quot;&gt;Repair sitemap and canonical conflicts&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/guides/technical-seo-audit-screaming-frog-search-console&quot;&gt;Compare crawl data with Search Console evidence&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;&lt;/nav&gt;
      &lt;div class=&quot;article-cta&quot;&gt;&lt;p class=&quot;cta-h&quot;&gt;Need the store URL rules turned into a fix plan?&lt;/p&gt;&lt;p&gt;FloxoLab can map filter combinations, pagination paths, canonical signals, internal discovery, and catalog drift into a prioritized ecommerce SEO implementation plan.&lt;/p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo-audit&quot; class=&quot;btn btn-primary article-cta-button&quot;&gt;Explore the SEO audit&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/guides/ecommerce-faceted-navigation-pagination&quot;&gt;FloxoLab&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/25631/faceted-navigation-and-pagination-for-ecommerce-seo</guid>
<pubDate>Mon, 31 Aug 2026 15:50:00 +0000</pubDate>
</item>
<item>
<title>Stop Scrolling Forever: 5+ Shadcn Pagination Fixes for Long Lists</title>
<link>https://coderlegion.com/16330/stop-scrolling-forever-5-shadcn-pagination-fixes-for-long-lists</link>
<description>&lt;p&gt;If you've ever searched something on &lt;strong&gt;Google&lt;/strong&gt;, you've already used pagination.&lt;/p&gt;
&lt;p&gt;Google has billions of results, and instead of loading everything at once, it breaks them into pages so users can browse step by step.&lt;/p&gt;
&lt;p&gt;The same idea applies to modern web apps.&lt;/p&gt;
&lt;p&gt;When your website or app has a lot of data, products, users, posts, or records, showing everything at once becomes messy and slow.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;That’s where &lt;strong&gt;Shadcn Pagination&lt;/strong&gt; helps.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you're building with &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://react.dev/&quot;&gt;React&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://nextjs.org/&quot;&gt;Next.js&lt;/a&gt;&lt;/strong&gt;, or &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://shadcnspace.com/&quot;&gt;shadcn/ui&lt;/a&gt;&lt;/strong&gt;, these &lt;strong&gt;Shadcn Pagination Components&lt;/strong&gt; can help you organize large datasets cleanly and improve user experience.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-is-shadcn-pagination-&quot;&gt;What Is Shadcn Pagination?&lt;/h3&gt;
&lt;p&gt;Pagination is a UI pattern used to split large content or datasets into multiple pages.&lt;/p&gt;
&lt;p&gt;Instead of rendering 500 items in one long list, pagination breaks them into smaller manageable chunks.&lt;/p&gt;
&lt;p&gt;Example use cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Product listings&lt;/li&gt;
&lt;li&gt;Blog archives&lt;/li&gt;
&lt;li&gt;Admin dashboard tables&lt;/li&gt;
&lt;li&gt;Search results&lt;/li&gt;
&lt;li&gt;Documentation pages&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Shadcn UI Pagination gives you a flexible and customizable way to build this pattern in modern React apps.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-developers-use-shadcn-pagination&quot;&gt;Why Developers Use Shadcn Pagination&lt;/h3&gt;
&lt;p&gt;As your app grows, your data grows too.&lt;/p&gt;
&lt;p&gt;Without proper pagination, performance drops and users struggle to navigate large datasets.&lt;/p&gt;
&lt;h4 id=&quot;benefits-of-pagination&quot;&gt;Benefits of Pagination&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Improves page load speed&lt;/li&gt;
&lt;li&gt;Makes large data easier to handle&lt;/li&gt;
&lt;li&gt;Gives users better navigation control&lt;/li&gt;
&lt;li&gt;Works well with APIs and server-side data&lt;/li&gt;
&lt;li&gt;Keeps UI structured and clean&lt;/li&gt;
&lt;li&gt;Easy to integrate into tables and lists&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;shadcn-pagination-examples-amp-variations&quot;&gt;Shadcn Pagination Examples &amp;amp; Variations&lt;/h3&gt;
&lt;p&gt;Stop struggling with messy lists. Today I’m sharing my favorite Shadcn pagination examples to help you build a cleaner, more professional web interface in minutes.&lt;/p&gt;
&lt;h3 id=&quot;floating-pill-pagination&quot;&gt;Floating Pill Pagination&lt;/h3&gt;
&lt;p&gt;A modern pill-style pagination component with rounded active states.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ik.imagekit.io/shadcnspace/Shadcn%20Pagination/Screenshot_1%20Pagination%2001%20-%20Floating%20Pill.png&quot; alt=&quot;Floating Pill Pagination&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;features&quot;&gt;Features&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Modern floating design&lt;/li&gt;
&lt;li&gt;Great for SaaS and dashboard UIs&lt;/li&gt;
&lt;li&gt;Easy to integrate into any React project&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;premium-ribbon-pagination&quot;&gt;Premium Ribbon Pagination&lt;/h3&gt;
&lt;p&gt;A more polished pagination design with premium visual styling.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ik.imagekit.io/shadcnspace/Shadcn%20Pagination/Screenshot_2%20Pagination%2002%20-%20Premium%20Ribbon.png&quot; alt=&quot;Premium Ribbon Pagination&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;features-1&quot;&gt;Features&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Premium ribbon-inspired appearance&lt;/li&gt;
&lt;li&gt;Best for high-end landing pages&lt;/li&gt;
&lt;li&gt;Clean active/hover states&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;interactive-jump-pagination&quot;&gt;Interactive Jump Pagination&lt;/h3&gt;
&lt;p&gt;Built for interfaces with many pages.&lt;/p&gt;
&lt;p&gt;Instead of forcing users to click repeatedly, this variant makes jumping across page ranges easier.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ik.imagekit.io/shadcnspace/Shadcn%20Pagination/Screenshot_3%20Pagination%2003%20-%20Interactive%20Jump.png&quot; alt=&quot;Interactive Jump Pagination&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;features-2&quot;&gt;Features&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Ideal for large datasets&lt;/li&gt;
&lt;li&gt;Better navigation for deep pagination&lt;/li&gt;
&lt;li&gt;Improves usability in data-heavy apps&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;⬇️ &lt;a rel=&quot;nofollow&quot; href=&quot;https://shadcnspace.com/components/pagination&quot;&gt;Get these Shadcn Paginations&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;pagination-with-next-previous-option&quot;&gt;Pagination with Next / Previous Option&lt;/h3&gt;
&lt;p&gt;Classic pagination with previous and next controls.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ik.imagekit.io/shadcnspace/Shadcn%20Pagination/Screenshot_4%20Pagination%20Ellipsis.png&quot; alt=&quot;Pagination with Next / Previous Option&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;features-3&quot;&gt;Features&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Includes directional navigation&lt;/li&gt;
&lt;li&gt;Familiar UI pattern&lt;/li&gt;
&lt;li&gt;Great for blogs and search pages&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;collapsible-pagination&quot;&gt;Collapsible Pagination&lt;/h3&gt;
&lt;p&gt;Minimal pagination without page numbers.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ik.imagekit.io/shadcnspace/Shadcn%20Pagination/Screenshot_5%20Pagination%205%20-%20Collapsible%20Pagination%20with%20NextPrevious%20Option.png&quot; alt=&quot;Collapsible Pagination&quot;&gt;&lt;/p&gt;
&lt;p&gt;Useful when page numbers are not necessary.&lt;/p&gt;
&lt;h4 id=&quot;features-4&quot;&gt;Features&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Previous / Next only&lt;/li&gt;
&lt;li&gt;Great for tables with row selectors&lt;/li&gt;
&lt;li&gt;Cleaner compact layout&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;basic-pagination&quot;&gt;Basic Pagination&lt;/h3&gt;
&lt;p&gt;Simple &amp;amp; straightforward page-number-based pagination component.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ik.imagekit.io/shadcnspace/Shadcn%20Pagination/Screenshot_6%20Simple%20Pagination.png&quot; alt=&quot;Basic Pagination&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;features-5&quot;&gt;Features&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Simple and lightweight&lt;/li&gt;
&lt;li&gt;Easy to customize&lt;/li&gt;
&lt;li&gt;Works in most use cases&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;⬇️ &lt;a rel=&quot;nofollow&quot; href=&quot;https://ui.shadcn.com/docs/components/base/pagination&quot;&gt;Get these Shadcn Paginations&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;key-features-of-shadcn-ui-pagination&quot;&gt;Key Features of Shadcn UI Pagination&lt;/h3&gt;
&lt;p&gt;Most modern &lt;strong&gt;Shadcn Pagination Variants&lt;/strong&gt; support:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Previous, next, and page controls&lt;/li&gt;
&lt;li&gt;Active page highlighting&lt;/li&gt;
&lt;li&gt;Client-side and server-side data handling&lt;/li&gt;
&lt;li&gt;Flexible component structure&lt;/li&gt;
&lt;li&gt;Keyboard accessibility&lt;/li&gt;
&lt;li&gt;Fully responsive layouts&lt;/li&gt;
&lt;li&gt;Minimal design that fits most UIs&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-pagination-matters-in-modern-web-apps&quot;&gt;Why Pagination Matters in Modern Web Apps&lt;/h3&gt;
&lt;p&gt;Pagination is not just about splitting content.&lt;/p&gt;
&lt;p&gt;It improves both &lt;strong&gt;performance&lt;/strong&gt; and &lt;strong&gt;usability&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Rendering too much data at once can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Slow down the page&lt;/li&gt;
&lt;li&gt;Increase API load&lt;/li&gt;
&lt;li&gt;Confuse users&lt;/li&gt;
&lt;li&gt;Hurt mobile experience&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A good pagination system keeps your UI fast, structured, and scalable.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;faq&quot;&gt;FAQ&lt;/h3&gt;
&lt;h4 id=&quot;does-pagination-help-with-seo-&quot;&gt;Does Pagination Help with SEO?&lt;/h4&gt;
&lt;p&gt;Yes. Pagination improves internal linking structure and helps search engines understand relationships between content pages.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;should-pagination-appear-on-every-page-&quot;&gt;Should Pagination Appear on Every Page?&lt;/h4&gt;
&lt;p&gt;No. Pagination should only be used where content is split across multiple views or datasets.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;is-pagination-useful-in-saas-dashboards-&quot;&gt;Is Pagination Useful in SaaS Dashboards?&lt;/h4&gt;
&lt;p&gt;Absolutely. Pagination is commonly used in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Admin panels&lt;/li&gt;
&lt;li&gt;Analytics dashboards&lt;/li&gt;
&lt;li&gt;User management tables&lt;/li&gt;
&lt;li&gt;Large data reports&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;Pagination is one of those small components that has a big impact on usability.&lt;/p&gt;
&lt;p&gt;Whether you're building a dashboard, blog, product listing, or admin panel, having the right &lt;strong&gt;Shadcn Pagination Component&lt;/strong&gt; makes your interface easier to use and easier to scale.&lt;/p&gt;
&lt;p&gt;Instead of building from scratch, use these &lt;strong&gt;Shadcn UI Pagination Examples&lt;/strong&gt; as a starting point and customize them to fit your project.&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;&lt;h4 id=&quot;looking-for-more-shadcn-pagination-components-&quot;&gt;Looking for More Shadcn Pagination Components?&lt;/h4&gt;
&lt;p&gt;Check out this curated collection of &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://shadcnspace.com/components/pagination&quot;&gt;Shadcn Pagination Components&lt;/a&gt;&lt;/strong&gt; to explore more modern pagination patterns for your React and Next.js projects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://ik.imagekit.io/shadcnspace/Shadcn%20Pagination/Shadcn%20Pagination%20Looking%20for%20more.jpg&quot; alt=&quot;Shadcn Pagination Looking for more img&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h5 id=&quot;share-your-pagination-component&quot;&gt;Share Your Pagination Component&lt;/h5&gt;
&lt;p&gt;Feel free to send it to me on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://peerlist.io/sanjayjoshi&quot;&gt;Peerlist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/in/isanjayjoshi&quot;&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://twitter.com/isanjayjoshi&quot;&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.facebook.com/iSanjayJoshi&quot;&gt;Facebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://instagram.com/isanjayjoshi&quot;&gt;Instagram&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;built-a-shadcn-pagination-variant-of-your-own-&quot;&gt;Built a &lt;strong&gt;Shadcn Pagination Variant&lt;/strong&gt; of your own?&lt;/h5&gt;
&lt;p&gt;I’d love to review it and feature it here.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/16330/stop-scrolling-forever-5-shadcn-pagination-fixes-for-long-lists</guid>
<pubDate>Fri, 01 May 2026 14:17:21 +0000</pubDate>
</item>
<item>
<title>Client side pagination is not good in some cases</title>
<link>https://coderlegion.com/4519/client-side-pagination-is-not-good-in-some-cases</link>
<description>&lt;h3 id=&quot;the-pagination-pitfall-a-react-spring-boot-cautionary-tale&quot;&gt;The Pagination Pitfall: A React + Spring Boot Cautionary Tale&lt;/h3&gt;
&lt;h4 id=&quot;the-setup-it-ll-be-fine-&quot;&gt;The Setup: &quot;It’ll Be Fine...&quot;&lt;/h4&gt;
&lt;p&gt;A few years ago, I was working on a dashboard application with a &lt;strong&gt;React frontend&lt;/strong&gt; and a &lt;strong&gt;Spring Boot backend&lt;/strong&gt;. The task seemed simple: display a list of users with pagination.&lt;/p&gt;
&lt;p&gt;One of the newer devs suggested:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;“Let’s just fetch everything once and paginate on the client side — it’ll be faster for the user.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We had maybe 500 users at the time, so… sure. Why not?&lt;/p&gt;
&lt;p&gt;And then we shipped it.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;the-plot-twist-growth-happens&quot;&gt;The Plot Twist: Growth Happens&lt;/h4&gt;
&lt;p&gt;A few months passed.&lt;/p&gt;
&lt;p&gt;Marketing launched a campaign that worked &lt;strong&gt;too well&lt;/strong&gt;.&lt;br&gt;
Suddenly, instead of 500 users, we had &lt;strong&gt;250,000+&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The dashboard became unusable. The browser would freeze, mobile devices would crash, and CPU usage would spike through the roof.&lt;br&gt;
Our once-smooth user experience turned into a memory-leaking nightmare.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;-the-mistake-client-side-pagination-at-scale&quot;&gt;⚠️ The Mistake: Client-Side Pagination at Scale&lt;/h4&gt;
&lt;p&gt;Client-side pagination works &lt;strong&gt;only&lt;/strong&gt; when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The dataset is small and controlled  &lt;/li&gt;
&lt;li&gt;The entire dataset can be loaded efficiently in the browser  &lt;/li&gt;
&lt;li&gt;You don’t expect explosive growth  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But when you're working with &lt;strong&gt;Spring Boot APIs&lt;/strong&gt; and &lt;strong&gt;React&lt;/strong&gt;, it's tempting to fetch all data via a single REST call, dump it into state, and let React handle the UI slicing.&lt;/p&gt;
&lt;p&gt;What’s wrong with that?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You're sending huge payloads over the wire  &lt;/li&gt;
&lt;li&gt;You're increasing memory usage on the frontend  &lt;/li&gt;
&lt;li&gt;You’re locking users into long initial load times  &lt;/li&gt;
&lt;li&gt;You make updates or filtering much harder  &lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;-the-fix-server-side-pagination-with-spring-boot-react&quot;&gt;✅ The Fix: Server-Side Pagination with Spring Boot + React&lt;/h4&gt;
&lt;p&gt;We refactored. Here’s what we did:&lt;/p&gt;
&lt;h5 id=&quot;backend-spring-boot-&quot;&gt;Backend (Spring Boot)&lt;/h5&gt;
&lt;p&gt;We used &lt;code&gt;Pageable&lt;/code&gt; from Spring Data:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@GetMapping(&quot;/users&quot;)
public Page&amp;lt;User&amp;gt; getUsers(Pageable pageable) {
    return userRepository.findAll(pageable);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Spring Boot handles page number, size, sorting, and total count under the hood.&lt;/p&gt;
&lt;h5 id=&quot;frontend-react-&quot;&gt;Frontend (React)&lt;/h5&gt;
&lt;p&gt;We called the API with query parameters like &lt;code&gt;?page=0&amp;amp;size=20&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const fetchUsers = async (page, size) =&amp;gt; {
  const res = await fetch(`/api/users?page=${page}&amp;amp;size=${size}`);
  const data = await res.json();
  setUsers(data.content);
  setTotalPages(data.totalPages);
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We then plugged this into a pagination UI. Now, we load &lt;strong&gt;only what we need&lt;/strong&gt;, keep response times fast, and keep the browser happy.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;React + Spring Boot&lt;/strong&gt; is a powerful combo — but scale with caution  &lt;/li&gt;
&lt;li&gt;Don’t optimize for “today’s data” unless you’re &lt;em&gt;certain&lt;/em&gt; it won’t grow  &lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Spring’s &lt;code&gt;Pageable&lt;/code&gt;&lt;/strong&gt; and let the database do the heavy lifting  &lt;/li&gt;
&lt;li&gt;Keep network traffic and frontend memory usage lean  &lt;/li&gt;
&lt;li&gt;Premature optimization is bad, but premature &lt;em&gt;de-optimization&lt;/em&gt; is worse  &lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;tl-dr&quot;&gt;TL;DR&lt;/h4&gt;
&lt;p&gt;Using client-side pagination for large or unknown datasets is like bringing a spoon to a firefight.&lt;/p&gt;
&lt;p&gt;It might work — for a while — but you’re setting yourself up for disaster.&lt;/p&gt;
&lt;p&gt; Use the right tools. Paginate smart. Scale with confidence.&lt;/p&gt;
</description>
<category>Java</category>
<guid isPermaLink="true">https://coderlegion.com/4519/client-side-pagination-is-not-good-in-some-cases</guid>
<pubDate>Fri, 08 Aug 2025 20:29:08 +0000</pubDate>
</item>
<item>
<title>Offset vs Cursor-based Pagination: Choosing The Right Pagination Strategy</title>
<link>https://coderlegion.com/1758/offset-vs-cursor-based-pagination-choosing-the-right-pagination-strategy</link>
<description>&lt;p&gt;Whether you’re building API endpoints or designing sleek interfaces, selecting the right pagination strategy can significantly influence user experience and system performance. By the end of this article, you will understand the two types of pagination strategies and know when to choose one over the other.&lt;/p&gt;
&lt;h3 id=&quot;what-is-pagination-amp-why-does-it-matter-&quot;&gt;What is Pagination &amp;amp; Why Does It Matter?&lt;/h3&gt;
&lt;p&gt;Pagination is the process of dividing large datasets into smaller, manageable chunks or pages to improve performance and usability. Without pagination:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Frontend apps&lt;/em&gt; would struggle with rendering thousands of records at once.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Backend APIs&lt;/em&gt; would waste resources fetching unnecessary data.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;two-types-of-pagination-strategy&quot;&gt;Two Types Of Pagination Strategy&lt;/h3&gt;
&lt;p&gt;During the course of my career, I have seen engineers use the wrong pagination approach when implementing features for their app. Understanding the two types of pagination strategies can make a significant difference in both the performance and user experience of software applications.&lt;/p&gt;
&lt;h4 id=&quot;offset-based-pagination&quot;&gt;Offset-Based Pagination&lt;/h4&gt;
&lt;p&gt;Offset-based pagination is a commonly used pagination pattern where the frontend specifies a page number and a page size (how many items per page).&lt;/p&gt;
&lt;p&gt;Here is a sample React component that makes a request to an API that is based on offset pagination&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function ProductList() {
  const [products, setProducts] = useState([]);
  const [page, setPage] = useState(1);

  const fetchProducts = async () =&amp;gt; {
    const response = await fetch(`/api/products?page=${page}&amp;amp;limit=10`);
    const data = await response.json();
    setProducts(data);
  };

  return (
    &amp;lt;div&amp;gt;
      {products.map(product =&amp;gt; &amp;lt;div key={product.id}&amp;gt;{product.name}&amp;lt;/div&amp;gt;)}
      &amp;lt;button onClick={() =&amp;gt; setPage(p =&amp;gt; p - 1)} disabled={page === 1}&amp;gt;
        Previous
      &amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setPage(p =&amp;gt; p + 1)}&amp;gt;Next&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A sample sql query to implement the pagination could look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT * FROM products LIMIT 10 OFFSET 20;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;pros-of-offset-based-pagination&quot;&gt;Pros of offset-based pagination&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;It is easy to implement on the backend and also easy to implement a&lt;br&gt;
frontend component for interacting with the paginated data.&lt;/li&gt;
&lt;li&gt;Users can conveniently jump to any specific page.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;cons-of-offset-based-pagination&quot;&gt;Cons of offset-based pagination&lt;/h4&gt;
&lt;h4 id=&quot;performance-issues-with-large-datasets-&quot;&gt;Performance issues with large datasets:&lt;/h4&gt;
&lt;p&gt;While it is possible for the frontend to request a specific page number, the database still has to scan all the previous rows in the table until it reaches the exact page number and retrieve the specified page size. This leads to a significant performance bottle-neck for very large datasets. Let me make this clearer. Imagine a dataset of 500,000 records. To request the last 20 records, the frontend will make a GET request similar to this: &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;GET /api/items?page=25000&amp;amp;limit=20
   
// OR using the offset parameter
   
GET /api/items?offset=499980&amp;amp;limit=20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means, the database must scan all 500,000 rows (even though the frontend only wants 20), skip the first 499,980 records (wasting CPU, I/O, and memory) and finally return the last 20. This leads to &lt;em&gt;slow queries&lt;/em&gt; (higher latencies) and &lt;em&gt;wasted resources&lt;/em&gt; (imagine 1000 users hitting page 25,000 simultaneously!)&lt;/p&gt;
&lt;h4 id=&quot;inconsistent-results-with-real-time-data&quot;&gt;Inconsistent results with real-time data&lt;/h4&gt;
&lt;p&gt;Offset-based pagination is not suitable for real-time data such as social media feeds because it can lead to duplicate and inconsistent results. This is why social media apps such as Facebook, Instagram, Twitter, etc., use infinite scroll (which is based on cursor pagination) for loading more data to the UI.&lt;/p&gt;
&lt;h4 id=&quot;cursor-based-pagination&quot;&gt;Cursor-based pagination&lt;/h4&gt;
&lt;p&gt;Cursor-based pagination uses a unique identifier known as a &lt;em&gt;cursor&lt;/em&gt; or &lt;em&gt;pointer&lt;/em&gt; as a reference point to fetch the next set of results. That is, each time the frontend makes an API call, in addition to sending back data, the API would send a unique identifier that the frontend will pass in the next request. Then the API would use that identifier as a reference point for sending the next set of data.&lt;/p&gt;
&lt;p&gt;Below is a sample React component that consumes an API that is based on cursor pagination:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function CommentsFeed() {
  const [comments, setComments] = useState([]);
  const [cursor, setCursor] = useState(null);

  const fetchComments = async () =&amp;gt; {
    const url = `/api/comments?limit=10${cursor ? `&amp;amp;cursor=${cursor}` : ''}`;
    const response = await fetch(url);
    const { data, nextCursor } = await response.json();
    setComments(prev =&amp;gt; [...prev, ...data]);
    setCursor(nextCursor);
  };

  return (
    &amp;lt;div&amp;gt;
      {comments.map(comment =&amp;gt; &amp;lt;div key={comment.id}&amp;gt;{comment.content}&amp;lt;/div&amp;gt;)}
      {cursor &amp;amp;&amp;amp; &amp;lt;button onClick={fetchComments}&amp;gt;Load More&amp;lt;/button&amp;gt;}
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;pros-of-cursor-based-pagination&quot;&gt;Pros of cursor-based pagination&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Efficient for large datasets since the database uses the unique&lt;br&gt;
identifier to retrieve the next set of data without having to scan&lt;br&gt;
previous records.&lt;/li&gt;
&lt;li&gt;Suitable for real-time data: Cursor based pagination does not lead to&lt;br&gt;
duplicate or inconsistent results when applied on datasets that&lt;br&gt;
update rapidly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;cons-of-cursor-based-pagination&quot;&gt;Cons of cursor-based pagination&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Users cannot jump to specific pages.&lt;/li&gt;
&lt;li&gt;It is slighltly more complex to implement.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;comparison-of-offset-vs-cursor&quot;&gt;Comparison of Offset vs. Cursor&lt;/h4&gt;
&lt;table&gt;
&lt;tr style=&quot;background-color: #000; color: #fff;&quot;&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Offset Pagination&lt;/th&gt;
&lt;th&gt;Cursor Pagination&lt;/th&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #000; color: #fff;&quot;&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Slow with large offsets&lt;/td&gt;
&lt;td&gt;Fast, even with big data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #000; color: #fff;&quot;&gt;
&lt;td&gt;&lt;strong&gt;Random Access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;❌ No (sequential only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #000; color: #fff;&quot;&gt;
&lt;td&gt;&lt;strong&gt;Real-time Data&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ Pages may shift&lt;/td&gt;
&lt;td&gt;✅ Stable &amp;amp; consistent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #000; color: #fff;&quot;&gt;
&lt;td&gt;&lt;strong&gt;Implementation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Simple&lt;/td&gt;
&lt;td&gt;Requires cursor tracking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #000; color: #fff;&quot;&gt;
&lt;td&gt;&lt;strong&gt;Use Case&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;E-commerce, dashboards&lt;/td&gt;
&lt;td&gt;Social media, activity logs&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Choosing the right pagination strategy depends on the context and requirements of your features. With the above insights, you're ready to paginate with precision—empowering your application to be both user-friendly and performant.&lt;/p&gt;
</description>
<category>Web Dev</category>
<guid isPermaLink="true">https://coderlegion.com/1758/offset-vs-cursor-based-pagination-choosing-the-right-pagination-strategy</guid>
<pubDate>Tue, 01 Apr 2025 08:52:38 +0000</pubDate>
</item>
</channel>
</rss>