getStaticProps — Build-Time Data Fetching in Next.js SSG
In this tutorial, you will learn about getstaticprops. We cover key concepts, practical examples, and best practices to help you master this topic.
getStaticProps fetches data at build time in Next.js, supplying props to page components and enabling fully static pre-rendered pages.
What You'll Learn
By the end of this tutorial, you'll understand how getStaticProps works, how to fetch data from various sources, handle errors, optimize build performance, and integrate with CMS and databases.
Why It Matters
getStaticProps is the core data-fetching mechanism for Next.js SSG. Knowing how to use it effectively determines build speed, data freshness, error handling, and the overall quality of your static site.
Real-World Use
A product documentation site fetches content from 500 markdown files during build. getStaticProps reads each file, converts it to HTML, and passes the result as props to the page component. The build completes in under 2 minutes and the site serves instantly.
getStaticProps Flow
graph TD
A[Build Process] --> B[next build]
B --> C[Find pages with
getStaticProps]
C --> D[Execute getStaticProps
for each page]
D --> E{Fetch successful?}
E -->|Yes| F[Return props
to page component]
E -->|No| G[notFound: true
or redirect]
F --> H[Render page to HTML]
H --> I[Write static file]
I --> J[CDN Deploy]
style D fill:#4a90d9,color:#fff
style F fill:#27ae60,color:#fff
style G fill:#e74c3c,color:#fff
Basic Data Fetching
// pages/posts.js
export default function Posts({ posts, buildTime }) {
if (!posts || posts.length === 0) {
return <p>No posts found.</p>;
}
return (
<div>
<h1>Blog Posts</h1>
<p className="build-time">
Generated: {new Date(buildTime).toLocaleDateString()}
</p>
<ul>
{posts.map(post => (
<li key={post.id}>
<h2>{post.title}</h2>
<p>{post.body.substring(0, 100)}...</p>
</li>
))}
</ul>
</div>
);
}
export async function getStaticProps() {
try {
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!res.ok) {
throw new Error(`Fetch failed: ${res.status}`);
}
const posts = await res.json();
return {
props: {
posts: posts.slice(0, 20),
buildTime: Date.now()
}
};
} catch (error) {
console.error('Failed to fetch posts:', error.message);
return {
props: {
posts: [],
buildTime: Date.now(),
error: error.message
}
};
}
}
Multiple Data Sources
// pages/product/[slug].js
export default function ProductPage({ product, reviews, related }) {
return (
<div>
<h1>{product.name}</h1>
<p className="price">${product.price}</p>
<div className="reviews">
<h2>Reviews ({reviews.length})</h2>
{reviews.map(review => (
<div key={review.id} className="review">
<p>{review.text}</p>
<p className="rating">
Rating: {'*'.repeat(review.rating)}
</p>
</div>
))}
</div>
<div className="related">
<h2>Related Products</h2>
{related.map(p => (
<a key={p.id} href={`/product/${p.slug}`}>{p.name}</a>
))}
</div>
</div>
);
}
export async function getStaticProps({ params }) {
const { slug } = params;
// Fetch multiple data sources in parallel
const [productRes, reviewsRes, relatedRes] = await Promise.all([
fetch(`https://api.example.com/products/${slug}`),
fetch(`https://api.example.com/products/${slug}/reviews`),
fetch(`https://api.example.com/products/${slug}/related`)
]);
if (!productRes.ok) {
return { notFound: true };
}
const product = await productRes.json();
const reviews = await reviewsRes.json();
const related = await relatedRes.json();
return {
props: {
product,
reviews: reviews.slice(0, 5),
related: related.slice(0, 4)
}
};
}
File System Data Source
// pages/docs/[slug].js
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';
const docsDirectory = path.join(process.cwd(), 'docs');
export default function DocPage({ content, frontmatter }) {
return (
<article>
<h1>{frontmatter.title}</h1>
<p className="meta">
Updated: {frontmatter.updated}
</p>
<div dangerouslySetInnerHTML={{ __html: content }} />
</article>
);
}
export async function getStaticPaths() {
const fileNames = fs.readdirSync(docsDirectory);
const paths = fileNames
.filter(file => file.endsWith('.md'))
.map(file => ({
params: { slug: file.replace(/\.md$/, '') }
}));
return { paths, fallback: false };
}
export async function getStaticProps({ params }) {
const filePath = path.join(docsDirectory, `${params.slug}.md`);
const fileContent = fs.readFileSync(filePath, 'utf8');
const { data: frontmatter, content } = matter(fileContent);
return {
props: {
content,
frontmatter
}
};
}
Common Mistakes
- Not handling fetch errors. Failed API calls at build time crash the build. Wrap fetches in try-catch and return fallback data or notFound.
- Fetching data that doesn't change between builds. Hardcoded config, static metadata, and constants should be imported directly, not fetched.
- Over-fetching in a single getStaticProps. Break large data requirements into separate API calls. Use Promise.all for parallel fetching.
- Storing secrets in returned props. Environment variables and API keys in props get serialized to the client. Use server-only imports and environment variables.
- Not Caching API responses locally. During development, every rebuild fetches from the API. Cache API responses to a local JSON file to speed up development builds.
Practice Questions
- What does getStaticProps return and how does it work?
- How do you handle a failed API call in getStaticProps?
- Can you use client-side data alongside getStaticProps data?
- How does getStaticProps know which props to pass to the page?
- What is the fallback option on getStaticPaths used for?
Challenge: Build a documentation site that reads from local markdown files, uses getStaticPaths to generate all doc pages, fetches additional data from an API in getStaticProps, and gracefully handles missing files.
FAQ
Mini Project
Create a documentation site with 10 markdown files, implement getStaticPaths to discover all files, use getStaticProps to read and parse each file, add error handling for missing files, and display the content with proper formatting.
What's Next
You've mastered getStaticProps. Now learn getStaticPaths in depth to handle dynamic routes and complex path generation.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro