Next.js getStaticProps
In modern web development, achieving the perfect balance between performance and dynamic content is crucial. Next.js, a popular React framework, provides powerful data fetching methods to help developers build fast and efficient websites. One of these methods is getStaticProps
, which enables you to fetch data at build time and use it to generate static HTML pages.
What is getStaticProps?
getStaticProps
is a Next.js function that allows you to fetch data at build time and pass it as props to a page component. This means the data is fetched when you build your application, not when a user requests the page. As a result, pages load faster because they're pre-rendered with the data already in place.
The function runs only on the server-side and never runs in the browser, making it ideal for accessing direct database queries, file system operations, or API calls without exposing sensitive information to the client.
When to Use getStaticProps
getStaticProps
is perfect for:
- Pages that can be pre-rendered ahead of time
- Data that doesn't change frequently
- SEO-critical pages where content needs to be indexed by search engines
- Pages where performance is a priority
Basic Syntax
Here's the basic structure of getStaticProps
:
// pages/example.js
function ExamplePage({ data }) {
return (
<div>
<h1>{data.title}</h1>
<p>{data.content}</p>
</div>
);
}
export async function getStaticProps() {
// Fetch data from an API, database, or file system
const data = { title: 'Hello', content: 'World' };
// Return the data as props
return {
props: {
data,
},
};
}
export default ExamplePage;
Step-by-Step Implementation
Let's walk through creating a page that fetches blog posts from an API at build time:
1. Create a Page Component
First, create a new page in your Next.js project:
// pages/blog.js
function BlogPage({ posts }) {
return (
<div>
<h1>My Blog</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</li>
))}
</ul>
</div>
);
}
export default BlogPage;
2. Implement getStaticProps
Now, let's add the getStaticProps
function to fetch the blog posts:
// Still in pages/blog.js
export async function getStaticProps() {
// In a real app, this would be an API call
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await res.json();
// Only keep the first 10 posts for this example
const limitedPosts = posts.slice(0, 10).map(post => ({
id: post.id,
title: post.title,
excerpt: post.body.substring(0, 100) + '...'
}));
return {
props: {
posts: limitedPosts,
},
};
}
3. Result
When you build this application, Next.js will:
- Execute the
getStaticProps
function - Fetch the posts from the API
- Generate an HTML page with the pre-rendered content
- Serve this static HTML to users for fast page loads
Advanced getStaticProps Features
Revalidation with ISR (Incremental Static Regeneration)
One limitation of static generation is that the content is fixed until you rebuild the site. Next.js solves this with Incremental Static Regeneration (ISR):
export async function getStaticProps() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return {
props: {
posts,
},
// Re-generate at most once every 10 seconds
revalidate: 10,
};
}
The revalidate
property tells Next.js to regenerate the page after the specified number of seconds if a request comes in. This gives you the performance benefits of static pages with the freshness of server-rendered content.
Handling Errors or Redirects
You can also handle errors or redirect users when needed:
export async function getStaticProps() {
const res = await fetch('https://api.example.com/posts');
// If the request failed, you can redirect or return a 404
if (!res.ok) {
return {
notFound: true, // This will return a 404 page
// OR redirect:
// redirect: {
// destination: '/error',
// permanent: false,
// },
};
}
const posts = await res.json();
return {
props: {
posts,
},
};
}
Context Parameter
getStaticProps
receives a context parameter which contains information like params
for dynamic routes:
// pages/posts/[id].js
export async function getStaticProps(context) {
const { id } = context.params;
const res = await fetch(`https://api.example.com/posts/${id}`);
const post = await res.json();
return {
props: {
post,
},
};
}
// You need to define getStaticPaths for dynamic routes
export async function getStaticPaths() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
const paths = posts.map((post) => ({
params: { id: post.id.toString() },
}));
return { paths, fallback: false };
}
Real-world Example: Building a Product Catalog
Let's create a more practical example of a product catalog for an e-commerce website:
// pages/products.js
function ProductCatalog({ products, lastUpdate }) {
return (
<div className="container">
<h1>Our Products</h1>
<p>Last updated: {new Date(lastUpdate).toLocaleString()}</p>
<div className="product-grid">
{products.map((product) => (
<div key={product.id} className="product-card">
<img
src={product.image}
alt={product.name}
width={200}
height={200}
/>
<h2>{product.name}</h2>
<p className="price">${product.price.toFixed(2)}</p>
<p>{product.description}</p>
<button>Add to Cart</button>
</div>
))}
</div>
</div>
);
}
export async function getStaticProps() {
try {
// In a real app, this would be your actual API or CMS endpoint
const res = await fetch('https://fakestoreapi.com/products');
if (!res.ok) {
throw new Error('Failed to fetch products');
}
const productsData = await res.json();
// Format the data as needed
const products = productsData.map(item => ({
id: item.id,
name: item.title,
price: item.price,
description: item.description.substring(0, 100) + '...',
image: item.image
}));
return {
props: {
products,
lastUpdate: new Date().toISOString(),
},
// Re-generate every hour
revalidate: 3600,
};
} catch (error) {
console.error('Error fetching products:', error);
// Return empty products if there's an error
return {
props: {
products: [],
lastUpdate: new Date().toISOString(),
error: 'Failed to load products'
},
revalidate: 60, // Try again more quickly if there was an error
};
}
}
export default ProductCatalog;
Performance Considerations
When using getStaticProps
, keep these tips in mind:
- Build time impact: More pages using
getStaticProps
will increase your build time. - Data size: Be mindful of how much data you're passing as props—large data can increase page weight.
- Revalidation frequency: Set reasonable revalidation intervals based on how often your data changes.
- API rate limits: Be careful with API calls at build time, especially with many pages.
Summary
getStaticProps
is a powerful feature in Next.js that allows you to fetch data at build time and generate static HTML pages with that data. This approach combines the performance benefits of static sites with the dynamic content capabilities normally associated with server rendering.
Key points to remember:
- It runs only at build time (and during revalidation with ISR)
- It's ideal for content that doesn't change frequently
- It improves performance by pre-rendering pages with data
- It never runs on the client, so you can safely access databases or APIs
- With
revalidate
, you can update static content without rebuilding
Exercises
- Create a Next.js page that uses
getStaticProps
to display a list of books from a mock API. - Implement
getStaticProps
with error handling that redirects to an error page if the API fetch fails. - Build a dynamic route (
[id].js
) that uses bothgetStaticPaths
andgetStaticProps
to generate individual pages for each item in a collection. - Implement Incremental Static Regeneration for a news website homepage that updates every 5 minutes.
Additional Resources
- Next.js Documentation on getStaticProps
- Incremental Static Regeneration Guide
- Data Fetching in Next.js
- Next.js Examples Repository
Happy coding with Next.js and getStaticProps
!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)