08 / 10

How do you build a deeply nested dynamic route like /shop/[category]/[subcategory]/[productId]? What are the pitfalls?

Difficulty: 6/10
dynamic routing, fallback handling, data fetching

Build deeply nested dynamic routes by creating a folder structure that mirrors the URL segments, using generateStaticParams at the deepest level to pre-render pages, and watching for pitfalls like waterfalls, missing error boundaries, and inefficient data fetching

Building a deeply nested dynamic route like /shop/[category]/[subcategory]/[productId] in Next.js involves creating a folder structure that directly maps to the URL segments. In the App Router, you'd create folders at app/shop/[category]/[subcategory]/[productId]/page.tsx. Each folder name in square brackets creates a dynamic segment that becomes a parameter in your component. While this is straightforward to implement, deeply nested routes introduce several pitfalls around data fetching efficiency, error handling, and performance that require careful architectural consideration .

Basic Folder Structure

The most significant pitfall with deeply nested routes is the potential for data fetching waterfalls. In the folder structure above, each segment level might have its own data requirements. The layout at shop/[category] might need category metadata, the layout at shop/[category]/[subcategory] might need subcategory data, and the product page needs product data. Without careful design, these fetches happen sequentially: first category, then subcategory (which depends on category), then product (which depends on both). This can add hundreds of milliseconds to page load time . The solution is to lift data fetching: fetch all needed data in the deepest component (the product page) or use parallel data fetching with Promise.all .

Pitfall 1 Solution: Parallel Data Fetching

For large e-commerce sites, generating all possible product pages with generateStaticParams at the deepest level can lead to extremely long build times. If you have 1000 categories, each with 100 subcategories, each with 1000 products, that's 100 million pages to generate—impossible. The solution is to use a combination of pre-rendering popular paths and on-demand generation with dynamicParams: true or fallback: 'blocking' . For deeply nested routes, you can also generate params at multiple levels: generate all categories at the first level, all subcategories at the second level, but only popular products at the deepest level, letting long-tail content generate on first visit .

Pitfall 2 Solution: Strategic generateStaticParams

In deeply nested routes, an error in fetching category data shouldn't necessarily break the entire page if product data is still available. Without proper error boundaries at each segment level, an error in any parent layout will cause the entire page to fail. The solution is to add error.tsx files at each level of the nesting . This allows graceful degradation: if the category sidebar fails to load, the main product content can still display with appropriate fallback UI. Each level should have its own error.tsx and loading.tsx files to provide progressively granular error recovery .

Pitfall 3 Solution: Granular Error Boundaries

As routes get deeper, passing params and fetched data down through multiple component levels becomes cumbersome. Server Components can't use React Context, so you either need to fetch data at each level (which may be inefficient) or pass props down through many layers. The solution is to lift data fetching to the deepest component that needs the data, as shown in the parallel fetching example, or use patterns like the Data Access Layer where each component fetches its own data efficiently with caching . For truly shared data, consider using React's cache() function to deduplicate identical requests across components .

Additional Pitfalls to Watch For
  1. 1

    Catch-all routes confusion: For deeply nested variable-depth routes, use [...slug] catch-all segments, but be careful with type safety—params become arrays .

  2. 2

    Search parameter management: Deep routes often need search params (filtering, sorting). Access them with searchParams in the page component or useSearchParams in client components with Suspense boundaries .

  3. 3

    Layout re-renders: Parent layouts re-render when child params change unless they're properly memoized or use parallel routes for independent sections .

  4. 4

    SEO and canonical URLs: Deeply nested routes may create duplicate content issues if the same product is accessible via multiple paths. Implement proper canonical tags .

Scenario Questions

0-2 years experience

  1. 1If you need to add a product detail page at /shop/[category]/[subcategory]/[productId] in a new Next.js app, how would you structure the files in the pages (or app) directory?
  2. 2What happens if a user navigates to /shop/electronics/phones without a productId? How would you handle that route?
  3. 3How would you retrieve the category, subcategory, and productId values inside getServerSideProps?

2-5 years experience

  1. 1We noticed that navigating from /shop/electronics/phones/123 to /shop/electronics/phones/124 triggers a full page reload. What could be causing that and how would you fix it?
  2. 2During a rollout, some product URLs return 404 even though the files exist. What debugging steps would you take to identify the issue?
  3. 3Explain the trade‑offs between using a catch‑all route ([...slug]) versus separate nested dynamic folders for this shop structure.

5-8 years experience

  1. 1At scale we have thousands of categories and products. How would you design the routing and data fetching to keep page load times low and avoid excessive serverless function cold starts?
  2. 2What are the implications of using getStaticPaths with fallback: 'blocking' for this three‑level route, and how would you decide between static generation and server‑side rendering?
  3. 3If we need to support SEO‑friendly URLs while also allowing deep linking from marketing campaigns, what edge cases in the routing logic must we guard against?

8+ years experience

  1. 1Our monorepo contains multiple teams each owning different parts of the shop. How would you structure the Next.js routing and shared utilities to allow independent deployment of new categories without breaking existing routes?
  2. 2We plan to migrate from file‑system routing to a custom route handler (e.g., middleware) to support locale prefixes and A/B testing. What architectural considerations and pitfalls should we anticipate for the existing deep nested routes?
  3. 3How would you set up automated testing and monitoring to catch regressions in dynamic route handling across all three levels as the product catalog evolves?

Follow-up Questions

  • What would you do if the productId segment should be optional?
  • How does Next.js prioritize static files over dynamic ones in this hierarchy?
  • How would you set up automated tests to verify these routes in CI?
Share

Share via WhatsApp, X, Facebook, LinkedIn or copy link. Open Graph preview enabled.