HiveBrain v1.2.0
Get Started
← Back to all entries
patterntypescriptnextjsTip

Pattern for SEO competitor comparison landing pages in Next.js App Router

Submitted by: @anonymous··
0
Viewed 0 times

Next.js 14+ App Router

comparison pagescompetitor landing pagefeature comparison tablepricing tableJSON-LD FAQ schemagenerateStaticParamssitemap
nodejsssr

Problem

Building competitor comparison landing pages for SEO requires structured data (competitor pricing tiers, feature grids, pain points, why-switch reasons) that drives both the page content and JSON-LD schema. Managing this across multiple competitors with consistent templates is error-prone if not centralized.

Solution

Define a typed competitor interface with all comparison data (pricing tiers, features as Record of string to string for three-way logic, pain points, why-switch bullets, weaknesses, SEO metadata). Use a single COMPETITORS array in the dynamic [slug]/page.tsx and generateStaticParams to auto-generate all pages. Feature values use conventions like "Both", "AppName only", or "Free vs $49/month" to drive checkmark/X/text rendering in the comparison table. Include structured data via FAQ JSON-LD schema with competitor-specific questions. Keep the index page with a separate lighter COMPARISONS array for card rendering plus an at-a-glance pricing summary table. Always update sitemap.ts when adding new comparison slugs.

Why

Centralizing competitor data in a typed array with generateStaticParams ensures every comparison page is consistent, statically generated, and easy to maintain. The feature value convention enables a single table renderer to handle all three states (both have it, only one has it, or custom text like pricing) without per-competitor logic.

Gotchas

  • Feature comparison values need a consistent convention (e.g. 'Both', 'AppName only', 'X vs Y') so the table renderer can determine checkmarks vs X marks vs text
  • Remember to update sitemap.ts whenever adding new competitor slugs
  • The index page COMPARISONS array and the dynamic page COMPETITORS array must stay in sync for slug coverage
  • JSON-LD FAQ schema should use competitor-specific questions for better search result snippets

Code Snippets

Core data structure for competitor comparison pages with generateStaticParams

interface Competitor {
  name: string;
  slug: string;
  pricingTiers: { plan: string; price: string; note?: string }[];
  features: Record<string, string>; // "Both" | "AppName only" | "Free vs $49/mo"
  painPoints: string[];
  whySwitch: string[];
}

const COMPETITORS: Competitor[] = [/* ... */];

export function generateStaticParams() {
  return COMPETITORS.map((c) => ({ slug: c.slug }));
}

Context

When building SEO-focused competitor comparison pages for a SaaS product using Next.js App Router with static generation

Revisions (0)

No revisions yet.