Next.js
I. Next.js Fundamentals
1. Introduction to Next.js
2. Next.js vs React
3. Project Setup
4. Folder Structure
5. Pages and Routing
6. Link and Navigation
7. Static Assets
8. CSS and Styling
II. Routing, Data & Rendering
9. Dynamic Routing
10. API Routes
11. Data Fetching Basics
12. getStaticProps
13. getServerSideProps
14. Incremental Static Regeneration
15. Rendering Strategies
16. Image Optimization
III. Advanced Next.js & Performance
17. Middleware
18. Authentication Basics
19. Authorization
20. Environment Variables
21. Performance Optimization
22. SEO with Next.js
23. Internationalization
24. Error Handling
IV. Projects, Deployment & Best Practices
25. Next.js Best Practices
26. Folder and Code Organization
27. Testing Next.js Apps
28. Security in Next.js
29. Next.js Interview Questions
30. Mini Project – Blog
31. Mini Project – Dashboard
32. Mini Project – Ecommerce
33. Mini Project – API Integration
34. Next.js Case Study
35. Real-World Use Cases
36. Project Planning
37. Final Project
38. Deployment with Vercel
39. Course Review
40. Career Roadmap
LESSON 12
getStaticProps
Build lightning-fast article pages with static site generation that pre-renders content at build time for maximum performance.
Every developer faces the same challenge: how to make websites blazingly fast while still showing dynamic content. NewsWave needs to display thousands of articles, but loading them from a database on every page visit would be slow. Users expect instant loading, especially for content that doesn't change frequently. That's wheregetStaticProps comes in. Think of it as a chef preparing all the meals before the restaurant opens. Instead of cooking when customers arrive, everything is ready to serve immediately.
Unlike React applications that fetch data after components mount, Next.js can fetch data during the build process. Your articles get rendered into HTML files ahead of time. When users visit your site, they receive pre-built pages instantly — no waiting for API calls or loading spinners.
Understanding Static Generation
Static generation means converting your dynamic React components into static HTML files during the build process. Picture a printing press that creates thousands of identical newspapers at once, rather than handwriting each copy when someone wants to read it. When you runnpm run build, Next.js calls your getStaticProps functions and generates HTML files for every page. These files sit on your server or CDN, ready to be delivered instantly. No database queries during page visits. No API calls from the browser. Just pure HTML served at lightning speed.
This approach works perfectly for content that doesn't change constantly. Blog posts, documentation, product pages, and news articles are ideal candidates. They update occasionally, but most visitors see the same content. Why regenerate the same HTML repeatedly when you can build it once?
The performance benefits are enormous. Static files load faster than dynamic pages. Search engines can crawl and index them easily. CDNs can cache them globally. Your server handles less load because it's serving files instead of processing requests.
Static Generation
HTML built once at build time. Lightning fast delivery. Perfect for content that changes infrequently.
Client-Side Rendering
HTML built in browser after loading. Slower initial load. Good for personalized content.
Basic getStaticProps Syntax
ThegetStaticProps function lives in your page components and runs exclusively on the server during build time. Never in the browser. It fetches data and passes it to your component as props.
Here's the fundamental structure every NewsWave article page needs:
// pages/articles/[slug].js - Individual article page
export async function getStaticProps() {
// This code runs at BUILD TIME, never in browser
return {
props: {
// Data passed to your component
}
}
}getStaticProps and must be exported from a page component. Next.js recognizes this function name and calls it during the build process. Your component receives the returned props as if they were passed from a parent component.
Let's build a real article page that fetches content before rendering:
// Mock database function - simulates fetching from CMS
const getArticleData = (slug) => {
// In real apps, this queries your database or CMS
return {
title: "Next.js 14 Performance Optimization Guide",
author: "Sarah Chen",
publishedAt: "2024-01-15",
content: "Modern web applications demand exceptional performance...",
category: "Tech",
viewCount: 2840
}
}export default function ArticlePage({ article }) {
// This component receives article data as props
return (
<div style={{ maxWidth: '800px', margin: '0 auto', padding: '20px' }}>
<h1>{article.title}</h1>
<p>By {article.author} • {article.publishedAt}</p>
<div>{article.content}</div>
<span>{article.viewCount} views</span>
</div>
)
}localhost:3000/articles/nextjs-performance — NewsWave
What just happened?
The component rendered with pre-fetched data as props. No loading states needed because the content was ready before the page loaded. Try this: Check the page source — you'll see the full HTML content, not empty divs waiting for JavaScript.
Fetching Real Data
Real applications fetch data from APIs, databases, or content management systems. The NewsWave team needs to pull articles from their CMS and generate static pages for each one. Here's howgetStaticProps handles external data sources.
The function runs in a Node.js environment, so you can use any server-side code. File system access, database queries, API calls to private endpoints — everything works because this code never reaches the browser.
// pages/articles/[slug].js
export async function getStaticProps({ params }) {
// params.slug contains the dynamic route parameter
const articleSlug = params.slug // "nextjs-performance" from URL
// Fetch from your CMS API (Strapi, Contentful, etc)
const response = await fetch(`https://api.newswave.com/articles/${articleSlug}`)
const article = await response.json()
return {
props: {
article // Passed to your component
}
}
}params object contains dynamic route parameters. For a file named [slug].js, params.slug gives you the actual slug from the URL. This lets you fetch specific content for each page.
Here's a more complete example that handles errors and provides fallback content:
export async function getStaticProps({ params }) {
try {
// Attempt to fetch article data
const response = await fetch(`https://api.newswave.com/articles/${params.slug}`)
if (!response.ok) {
// Article not found or API error
return {
notFound: true // Shows 404 page
}
}
const article = await response.json()
return {
props: { article },
revalidate: 3600 // Revalidate every hour
}
} catch (error) {
console.error('Failed to fetch article:', error)
return {
notFound: true
}
}
}Build Process
> next build
Running getStaticProps for /articles/[slug]...
✓ Fetching nextjs-performance
✓ Fetching react-18-features
✓ Fetching typescript-best-practices
✓ Generated 3 static pages in /articles
What just happened?
Next.js called getStaticProps for each article during build time. Failed fetches return 404 pages instead of breaking the build. The revalidate option enables Incremental Static Regeneration. Try this: Deploy your site and watch build logs to see each page being generated.
Working with Dynamic Routes
Dynamic routes like[slug].js create a challenge for static generation. Next.js needs to know which pages to build ahead of time, but your slugs come from dynamic data. How can it generate pages for articles that don't exist yet at build time?
This is where getStaticPaths comes in. Think of it as providing a guest list to a party planner. You tell Next.js exactly which pages to pre-render by providing all possible parameter values.
The function returns an array of paths to generate. Each path object contains the parameters needed for that page. For NewsWave articles, you'd return all the article slugs from your CMS:
// pages/articles/[slug].js
export async function getStaticPaths() {
// Fetch all article slugs from your CMS
const response = await fetch('https://api.newswave.com/articles')
const articles = await response.json()
// Generate paths for each article
const paths = articles.map((article) => ({
params: { slug: article.slug }
}))
return {
paths, // Array of pages to pre-render
fallback: false // Show 404 for unknown paths
}
}fallback property controls what happens when someone visits a path not returned by getStaticPaths. Setting it to false means Next.js shows a 404 page for unknown routes. This works well when you know all possible paths at build time.
Here's a complete example showing how both functions work together:
// Static paths generation - runs at build time
export async function getStaticPaths() {
// Mock function - replace with your CMS query
const articles = [
{ slug: 'nextjs-14-features' },
{ slug: 'react-server-components' },
{ slug: 'typescript-migration-guide' }
]
const paths = articles.map(article => ({
params: { slug: article.slug }
}))
return { paths, fallback: false }
}// Data fetching for each path - runs at build time
export async function getStaticProps({ params }) {
// Mock article data - replace with CMS fetch
const articles = {
'nextjs-14-features': {
title: 'Next.js 14: Revolutionary New Features',
author: 'Alex Rodriguez',
content: 'Next.js 14 introduces groundbreaking improvements...',
publishedAt: '2024-01-20',
category: 'Tech'
}
}
const article = articles[params.slug]
return {
props: { article }
}
}Static Generation Process
1. getStaticPaths() → returns array of slugs to build
2. getStaticProps() → called once for each slug
3. Component renders → generates static HTML file
✓ Result: Pre-built pages ready to serve instantly
What just happened?
Next.js generated three static HTML files during build time. Each file contains pre-rendered content with no JavaScript required to display the initial content. Users get instant page loads with full SEO benefits. Try this: Build and examine the .next/server/pages directory to see the generated files.
Return Options and Configuration
The object returned bygetStaticProps has several powerful options beyond just props. These options control caching, regeneration, and error handling. Understanding them helps you build more robust applications.
The revalidate option enables Incremental Static Regeneration (ISR). Instead of rebuilding your entire site when content changes, ISR updates individual pages in the background. It's like having a smart cache that refreshes automatically.
export async function getStaticProps() {
const article = await fetchArticleData()
return {
props: { article },
revalidate: 60 // Regenerate page every 60 seconds if requested
}
}notFound option tells Next.js to show a 404 page instead of rendering your component. This prevents broken pages when data doesn't exist:
export async function getStaticProps({ params }) {
const article = await fetchArticle(params.slug)
// Article doesn't exist in CMS
if (!article) {
return {
notFound: true // Shows 404 page
}
}
return {
props: { article }
}
}redirect option handles URL changes and content reorganization. Maybe NewsWave moved some articles to new paths:
export async function getStaticProps({ params }) {
const article = await fetchArticle(params.slug)
// Article moved to new URL structure
if (article.redirectTo) {
return {
redirect: {
destination: article.redirectTo,
permanent: true // HTTP 301 redirect
}
}
}
return {
props: { article }
}
}export async function getStaticProps({ params, preview = false }) {
try {
// Fetch article with preview support
const article = await fetchArticle(params.slug, { preview })
// Handle missing content
if (!article) {
return { notFound: true }
}
// Handle redirected content
if (article.status === 'moved') {
return {
redirect: {
destination: `/articles/${article.newSlug}`,
permanent: true
}
}
}
// Return successful response
return {
props: {
article,
preview
},
revalidate: preview ? 1 : 3600, // Faster revalidation in preview
}
} catch (error) {
console.error('getStaticProps error:', error)
return { notFound: true }
}
}ISR Request Flow
User visits page → Serve cached static page instantly
If revalidate time passed → Trigger background regeneration
New content ready → Next request gets updated page
✓ Users always get fast responses, content stays fresh
What just happened?
The function handles multiple scenarios gracefully. Missing content shows 404 pages instead of errors. Redirects preserve SEO when URLs change. ISR keeps content fresh without slow rebuilds. Try this: Add console.log statements to see when getStaticProps runs during development vs production.
Best Practices and Performance Tips
Successful static site generation requires following proven patterns. The NewsWave team learned these lessons while scaling to thousands of articles. Small mistakes ingetStaticProps can cause slow builds or runtime errors.
Keep your data fetching focused and efficient. Don't fetch unnecessary data just because you can. Each API call during build time slows down your deployment. Fetch exactly what your component needs for that specific page:
// ❌ Bad: Fetches too much data
export async function getStaticProps({ params }) {
const allArticles = await fetchAllArticles() // Unnecessary
const categories = await fetchAllCategories() // Not needed for article page
const article = allArticles.find(a => a.slug === params.slug)
return { props: { article, categories, allArticles } }
}
// ✅ Good: Fetches only what's needed
export async function getStaticProps({ params }) {
const article = await fetchArticle(params.slug)
return { props: { article } }
}export async function getStaticProps({ params }) {
try {
const article = await fetchArticle(params.slug)
const relatedArticles = await fetchRelatedArticles(article.categoryId)
.catch(() => []) // Fallback to empty array if related articles fail
return {
props: {
article,
relatedArticles
}
}
} catch (error) {
console.error(`Failed to build article ${params.slug}:`, error)
return { notFound: true }
}
}export async function getStaticProps({ params }) {
const article = await fetchArticle(params.slug)
// Different revalidation based on content type
const revalidateInterval = {
'breaking-news': 300, // 5 minutes
'tech': 3600, // 1 hour
'documentation': 86400, // 24 hours
'tutorial': 604800 // 1 week
}
return {
props: { article },
revalidate: revalidateInterval[article.category] || 3600
}
}// Production-ready getStaticProps for NewsWave
export async function getStaticProps({ params, preview = false }) {
const startTime = Date.now()
try {
// Parallel data fetching for better performance
const [article, metadata] = await Promise.all([
fetchArticle(params.slug, { preview }),
fetchSiteMetadata().catch(() => null) // Optional data
])
if (!article) {
console.log(`Article not found: ${params.slug}`)
return { notFound: true }
}
// Log build performance in development
if (process.env.NODE_ENV === 'development') {
console.log(`Built ${params.slug} in ${Date.now() - startTime}ms`)
}
return {
props: {
article,
metadata,
buildTime: new Date().toISOString()
},
revalidate: preview ? 60 : 3600
}
} catch (error) {
console.error(`getStaticProps error for ${params.slug}:`, error)
// In development, show error details
if (process.env.NODE_ENV === 'development') {
throw error
}
// In production, fail gracefully
return { notFound: true }
}
}Common Mistakes to Avoid
Never use browser-only APIs like localStorage in getStaticProps. Don't fetch user-specific data that should be personalized. Avoid massive data fetching that slows builds. Always handle API errors to prevent build failures.
Quiz
1. The NewsWave team wants to understand when getStaticProps runs. When does Next.js execute this function?
2. NewsWave has dynamic article routes like /articles/[slug]. Which function must you export alongside getStaticProps to tell Next.js which pages to pre-render?
3. What should getStaticProps return when NewsWave can't find an article in the CMS to prevent showing a broken page?
Up Next: getServerSideProps
Learn when to render pages on every request instead of at build time for dynamic, personalized content that changes frequently.