SalakCode SalakCode
Rendering

Static Site Generation

Pre-render pages at build time

Beginner
ssg jamstack nextjs gatsby

Definition

Static Site Generation (SSG) is the process of generating HTML pages at build time. These pre-rendered pages can be served directly from a CDN, resulting in fast load times, improved security, and better scalability compared to server-rendered applications.

How SSG Works

Build Time:
1. Fetch data from APIs/CMS
2. Generate HTML for each page
3. Output static files

Deployment:
1. Upload to CDN
2. Serve globally
3. No server needed at runtime

Next.js Implementation

getStaticProps

// pages/blog/[slug].js
export async function getStaticProps({ params }) {
  // Runs at build time
  const post = await fetchPost(params.slug);
  
  return {
    props: {
      post,
    },
    // Revalidate page every 60 seconds (ISR)
    revalidate: 60,
  };
}

export async function getStaticPaths() {
  // Generate pages for all posts at build time
  const posts = await fetchAllPosts();
  
  return {
    paths: posts.map((post) => ({
      params: { slug: post.slug },
    })),
    // Fallback: true = generate on first request
    fallback: 'blocking',
  };
}

export default function BlogPost({ post }) {
  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  );
}

Incremental Static Regeneration (ISR)

export async function getStaticProps() {
  const data = await fetchData();
  
  return {
    props: { data },
    // Page regenerates in background every 10 seconds
    revalidate: 10,
    
    // Don't fail build if API is down
    notFound: !data,
  };
}

Benefits

1. Performance

// Static HTML loads instantly
// No database queries at request time
// CDN caching built-in

// Lighthouse scores typically:
// Performance: 95-100
// SEO: 100
// Best Practices: 100

2. Security

// No server to hack
// No database connections
// No runtime vulnerabilities
// Immutable deployments

3. Scalability

// Serve from CDN edge locations
// Handle millions of requests
// No server scaling needed
// Global distribution built-in

Use Cases

Perfect for SSG:

  • Marketing sites
  • Documentation
  • Blogs
  • E-commerce product pages
  • Landing pages

Not suitable for:

  • User dashboards (personalized)
  • Real-time data
  • Authenticated content
  • Search results

SSG with Data Sources

Headless CMS

// Contentful
import { createClient } from 'contentful';

const client = createClient({
  space: process.env.CONTENTFUL_SPACE_ID,
  accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
});

export async function getStaticProps() {
  const entries = await client.getEntries({
    content_type: 'blogPost',
  });
  
  return {
    props: {
      posts: entries.items,
    },
  };
}

Markdown/MDX

import { readFileSync, readdirSync } from 'fs';
import { join } from 'path';
import matter from 'gray-matter';

export async function getStaticProps() {
  const postsDirectory = join(process.cwd(), 'posts');
  const filenames = readdirSync(postsDirectory);
  
  const posts = filenames.map((filename) => {
    const filePath = join(postsDirectory, filename);
    const fileContents = readFileSync(filePath, 'utf8');
    const { data, content } = matter(fileContents);
    
    return {
      slug: filename.replace(/\.md$/, ''),
      frontmatter: data,
      content,
    };
  });
  
  return { props: { posts } };
}

Deployment

Vercel

# Zero-config deployment
vercel --prod

# Automatic Git integration
# Preview deployments for PRs
# Edge network included

Netlify

# Build command
npm run build

# Publish directory
out/

# Automatic form handling
# Branch previews

Cloudflare Pages

# Build command
npm run build

# Build output directory
out/

# Integrated with Workers

Hybrid Approaches

Static + Client-side

// Pre-render static parts
// Fetch dynamic data on client

function Page({ staticData }) {
  const [dynamicData, setDynamicData] = useState(null);
  
  useEffect(() => {
    // Fetch personalized data
    fetchUserData().then(setDynamicData);
  }, []);
  
  return (
    <div>
      <StaticContent data={staticData} />
      {dynamicData && <UserContent data={dynamicData} />}
    </div>
  );
}

Static + API Routes

// pages/api/search.js
export default function handler(req, res) {
  const { query } = req.query;
  const results = searchIndex(query);
  res.status(200).json(results);
}

// Client-side search
function Search() {
  const [results, setResults] = useState([]);
  
  const search = async (query) => {
    const res = await fetch(`/api/search?query=${query}`);
    const data = await res.json();
    setResults(data);
  };
  
  return (
    <div>
      <input onChange={(e) => search(e.target.value)} />
      <Results items={results} />
    </div>
  );
}
Key Takeaway

SSG pre-renders HTML at build time for maximum performance and security. Use it for content that doesn’t change frequently. Combine with ISR for near-real-time updates, and add client-side JavaScript for dynamic functionality. Deploy to CDNs for global scale.

Resources

Related Topics