Skip to content

getStaticProps — Build-Time Data Fetching in Next.js SSG

DodaTech Updated 2026-06-28 4 min read

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

  1. Not handling fetch errors. Failed API calls at build time crash the build. Wrap fetches in try-catch and return fallback data or notFound.
  2. Fetching data that doesn't change between builds. Hardcoded config, static metadata, and constants should be imported directly, not fetched.
  3. Over-fetching in a single getStaticProps. Break large data requirements into separate API calls. Use Promise.all for parallel fetching.
  4. Storing secrets in returned props. Environment variables and API keys in props get serialized to the client. Use server-only imports and environment variables.
  5. 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

  1. What does getStaticProps return and how does it work?
  2. How do you handle a failed API call in getStaticProps?
  3. Can you use client-side data alongside getStaticProps data?
  4. How does getStaticProps know which props to pass to the page?
  5. 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

Can getStaticProps access the request object?

No. getStaticProps runs at build time, not request time. There is no request object. Use getServerSideProps if you need request context.

What happens if getStaticProps takes too long?

Build time increases. Next.js doesn't time out getStaticProps, but vercel.app has a 60-second limit for function execution. Optimize or use ISR for slow fetches.

Can I use database queries in getStaticProps?

Yes. You can query databases directly during build. This is common for SSG sites that read from a local database or cached API.

Does getStaticProps support TypeScript?

Yes. Type the return type explicitly for better IDE support. Use InferGetStaticPropsType for the props type on the component.

Can I use getStaticProps with client-side routing?

Yes. getStaticProps provides initial data. Use SWR or React Query for client-side updates without rebuilding.

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