Use static rendering where possible and avoid unnecessary client JS. If there is one sentence that summarises everything a marketing site built in Next.js should optimise for, that is it. Marketing sites have a specific set of requirements that differ fundamentally from web applications — they need to load instantly for cold visitors arriving from search engines, social media, and paid ads; they need to rank in Google; they need to convert; and they need to be maintainable by a small team over years, not months. Next.js is the best framework available for this use case in 2026, but only if you use it correctly.
This guide covers the rendering decisions, performance patterns, SEO implementation, and architectural choices that separate Next.js marketing sites that perform from ones that technically work but fail on the metrics that matter.
Choose the Right Rendering Strategy for Every Route
The most consequential decision in a Next.js marketing site is how each page is rendered. Get this wrong, and every other optimisation is building on a weak foundation. Next.js App Router supports four rendering modes — and the right choice depends entirely on the nature of the content.
Rendering Mode | How It Works | Best For |
|---|---|---|
Static (SSG) | HTML generated at build time, served from CDN | Landing pages, blog posts, pricing, about |
ISR | Static with background revalidation on a timer | Content that changes occasionally (blog lists, testimonials) |
SSR | HTML is generated per request on the server | Personalised pages, auth-gated content |
Client (CSR) | HTML generated in the browser via JavaScript | Interactive widgets, user dashboards |
==For a marketing site, the rule is simple: every public-facing page should be Static or ISR. SSR and CSR should be the exception, never the default.==
A homepage rendered statically and served from Vercel's edge network loads in under 100ms for users worldwide. The same page rendered server-side on every request introduces 200–800ms of server latency before a single byte reaches the browser. At the scale of a marketing site receiving paid traffic at £5 per click, that latency difference is a measurable revenue impact.
The App Router Default is Server Components — Use Them
In Next.js App Router, every component is a React Server Component by default. This means it renders on the server; its JavaScript is never sent to the browser, and it can fetch data directly without an API layer. ==This is the single biggest performance win Next.js 13+ offers, and most teams underuse it.==
The practical rule:
Use Server Components for everything that displays data — headers, navigation, content sections, cards, footers
Use Client Components (
"use client") only for interactivity — forms, dropdowns, modals, carousels, anything withuseStateoruseEffectNever add
"use client"to a component just because it's convenient — push interactivity as far down the component tree as possible
app/
├── page.tsx ← Server Component (static, no JS shipped)
├── components/
│ ├── HeroSection.tsx ← Server Component
│ ├── NavMenu.tsx ← Server Component (wrapper)
│ └── MobileMenu.tsx ← Client Component (toggle state only)
==The goal is to ship the minimum possible JavaScript to the browser. Every kilobyte of JS is a kilobyte the user's device must download, parse, and execute before the page is interactive.==
Image Optimisation Is Non-Negotiable
Images are the largest contributor to page weight on marketing sites. Hero images, team photos, product screenshots, blog cover images — unoptimised, these will destroy your LCP score and your conversion rate simultaneously.
Always Use the Next.js <Image> Component
The next/image The component does six things automatically that you would otherwise have to implement manually:
Converts to WebP/AVIF — 30–50% smaller than JPEG at equivalent quality
Generates responsive
srcset— serves the correctly sized image for every viewportLazy loads by default — images below the fold are not downloaded until needed
Prevents layout shift — reserves the correct space before the image loads, protecting your CLS score
Optimises on demand — images are processed at request time and cached at the CDN edge
Supports
priority— marks hero images for eager loading andfetchpriority="high"
/* ✅ Correct — hero image above the fold */
<Image
src="/images/hero.webp"
alt="Snappy-Fix web development services"
width={1200}
height={630}
priority // ← preloads this image, improves LCP
sizes="100vw"
/>
/* ✅ Correct — content image below the fold */
<Image
src="/images/feature.webp"
alt="Fast website performance dashboard"
width={600}
height={400}
loading="lazy" // ← default, explicit for clarity
sizes="(max-width: 768px) 100vw, 50vw"
/>
Common Image Mistakes to Avoid
❌ Using
<img>instead of<Image>— loses all automatic optimisation❌ Missing
alttext — fails accessibility and image SEO simultaneously❌ Missing
sizesprop — Next.js cannot generate an accuratesrcsetwithout it❌ Adding
priorityto every image — this defeats the purpose; only the hero gets it❌ Using enormous source images — even with optimisation, start with correctly sized source files
SEO Implementation in Next.js App Router
Leverage image optimisation and metadata for SEO. The Metadata API in Next.js App Router is the cleanest, most powerful SEO implementation available in any React framework. It generates <head> tags server-side, which means search engine crawlers see complete metadata in the raw HTML — no client-side injection, no hydration delay.
Static Metadata for Fixed Pages
// app/page.tsx — Homepage
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Snappy-Fix Technologies | Web Development Nigeria',
description: 'High-performance websites, web applications, and free online tools built by the Snappy-Fix team.',
keywords: 'web development Nigeria, Next.js agency, fast websites',
openGraph: {
title: 'Snappy-Fix Technologies',
description: 'We build fast, scalable digital products.',
url: 'https://www.snappy-fix.com',
siteName: 'Snappy-Fix',
images: [{ url: '/images/og-home.png', width: 1200, height: 630 }],
type: 'website',
},
twitter: {
card: 'summary_large_image',
title: 'Snappy-Fix Technologies',
description: 'We build fast, scalable digital products.',
images: ['/images/og-home.png'],
},
alternates: {
canonical: 'https://www.snappy-fix.com',
},
robots: {
index: true,
follow: true,
},
}
Dynamic Metadata for Content Pages
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await getBlogDetails(params.slug)
return {
title: `${post.meta_title || post.title} | Snappy-Fix Blog`,
description: post.meta_desc,
openGraph: {
title: post.title,
type: 'article',
publishedTime: post.published_at,
images: [{ url: post.thumbnail_url, width: 1200, height: 630 }],
},
alternates: {
canonical: `https://www.snappy-fix.com/blog/${post.slug}`,
},
}
}
The Complete SEO Metadata Checklist
Every public page on your marketing site should have all of these:
✅ Unique
titletag — 50–60 characters, primary keyword near the front✅ Unique
description— 140–155 characters, includes a call to action✅
canonicalURL — prevents duplicate content penalties✅
og:title,og:description,og:image— controls social sharing appearance✅
twitter:card— controls Twitter/X card appearance✅
robots— explicitly setindex: trueon public pages✅ JSON-LD structured data —
Organization,WebSite,BreadcrumbListat minimum
Folder Structure and Architecture for Long-Term Maintainability
Organise components and routes cleanly for long-term maintainability. A marketing site that starts with a clear architecture survives team changes, redesigns, and feature additions. One that starts without structure becomes unmaintainable within six months.
The Recommended Folder Structure
src/
├── app/ # Next.js App Router — routes only
│ ├── (marketing)/ # Route group — shared marketing layout
│ │ ├── page.tsx # Homepage
│ │ ├── about/page.tsx
│ │ ├── pricing/page.tsx
│ │ └── blog/
│ │ ├── page.tsx # Blog listing
│ │ └── [slug]/page.tsx # Blog detail
│ ├── layout.tsx # Root layout
│ └── not-found.tsx
├── components/
│ ├── ui/ # Primitive components (Button, Input, Badge)
│ ├── layout/ # Layout components (Navbar, Footer, Section)
│ ├── sections/ # Page section components (Hero, Features, CTA)
│ └── blog/ # Blog-specific components
├── lib/
│ ├── api/ # API service functions
│ └── utils/ # Utility functions
├── styles/ # Global CSS, tiptap-output.css
└── types/ # TypeScript type definitions
==Route groups (marketing) allow you to share a layout across multiple routes without that group name appearing in the URL. This keeps URLs clean while keeping layout logic organised.==
Architecture Rules That Prevent Decay
Rule | Why It Matters |
|---|---|
Routes contain no logic |
|
Components are pure | A component receives props and renders UI — no API calls inside |
Data fetching lives in | One place to find all API calls, easy to mock in tests |
Types live in | Shared types are never duplicated across files |
No barrel exports from | Prevents circular dependencies in the App Router |
Performance Checklist Before Every Deploy
Before shipping any marketing site built in Next.js, run through this checklist:
Rendering
✅ All public pages are Static or ISR — confirmed in
.next/server/app/build output✅ No unnecessary
"use client"directives on non-interactive components✅ Dynamic imports used for heavy third-party scripts (analytics, chat widgets, maps)
Images
✅ All images use
next/image✅ Hero image has
priorityprop✅ All images have descriptive
alttext✅
sizesprop set correctly on all images
JavaScript
✅ Bundle analysed with
@next/bundle-analyzer✅ No large libraries imported for single functions
✅ Third-party scripts loaded with
next/scriptusingstrategy="lazyOnload"
SEO
✅ Every page has a unique title and description
✅ Canonical URLs set on all pages
✅ Open Graph images specified
✅ JSON-LD structured data validated
✅
robots.txtandsitemap.xmlgenerated and submitted
Core Web Vitals
✅ LCP under 2.5s on mobile (test with PageSpeed Insights, not just DevTools)
✅ CLS under 0.1 — all images and embeds have explicit dimensions
✅ INP under 200ms — no long tasks blocking the main thread



