Production Engineering/
Lesson

Every time a user visits a traditional server-rendered page, the server runs code, queries a database, and builds the HTML from scratch. JAMstack turns that around: build the HTML once at deploy time, serve the static files from a CDNWhat is cdn?Content Delivery Network - a network of servers around the world that caches your files and serves them from the location closest to the user, making pages load faster., and let client-side JavaScript handle anything dynamic. The result is pages that load instantly because the server has already done all the work.

Traditional vs JAMstack request flow

The fundamental difference is when the HTML is generated.

Traditional (every request):
  User requests page
  → Server processes request
  → Database query runs
  → HTML is rendered
  → Response sent (300-2000ms)

JAMstack (every deploy):
  Build time: fetch data → generate HTML → upload to CDN
  Request time: user requests page → CDN serves file instantly (~50ms)

Serving a pre-built file from a CDNWhat is cdn?Content Delivery Network - a network of servers around the world that caches your files and serves them from the location closest to the user, making pages load faster. is orders of magnitude faster than running server code on every request.

02

The three parts of JAMstack

JavaScript handles dynamic behavior after the initial page load, fetching comments, handling form submissions, updating state in the browser.

APIs provide the backend, serverlessWhat is serverless?A hosting model where individual functions run on demand and the platform handles all server management, scaling, and uptime for you. functions, third-party services (Stripe, Auth0, Algolia), or your own RESTWhat is rest?An architectural style for web APIs where URLs represent resources (nouns) and HTTP methods (GET, POST, PUT, DELETE) represent actions on those resources./GraphQLWhat is graphql?A query language for APIs where clients specify the exact shape of data they need in a single request, avoiding over-fetching and under-fetching. APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses..

Markup is the pre-built HTML. A static site generator fetches your content at build time and outputs HTML files ready for the CDNWhat is cdn?Content Delivery Network - a network of servers around the world that caches your files and serves them from the location closest to the user, making pages load faster..

03

Static site generators

The generator is what turns your content into HTML files at build time.

// Next.js: getStaticProps runs at BUILD TIME, not request time
export async function getStaticProps() {
  const posts = await fetch('https://api.example.com/posts').then(r => r.json());
  return {
    props: { posts },
    revalidate: 3600 // ISR: re-generate after 1 hour
  };
}

export default function Home({ posts }) {
  return (
    <div>
      {posts.map(post => <article key={post.id}>{post.title}</article>)}
    </div>
  );
}
---
// Astro: data fetched at build time
const posts = await fetch('/api/posts').then(r => r.json());
---
<ul>
  {posts.map(post => <li>{post.title}</li>)}
</ul>
04

Tool ecosystem

CategoryOptionsNotes
Static generatorsNext.js, Astro, Gatsby, Hugo, 11tyNext.js most popular for React devs
Headless CMSContentful, Sanity, StrapiManage content, expose via API
Hosting/CDNVercel, Netlify, Cloudflare PagesDeploy with git push
Dynamic featuresServerless functions, Auth0, AlgoliaBolt on what you need
05

Adding dynamic features

Static pages don't mean static experiences. You add interactivity by fetching data client-side after the initial page load.

function BlogPost({ post }) {
  const [comments, setComments] = useState([]);

  useEffect(() => {
    // Static page, but dynamic comments loaded client-side
    fetch(`/api/comments?post=${post.id}`)
      .then(r => r.json())
      .then(setComments);
  }, [post.id]);

  return (
    <article>
      <h1>{post.title}</h1>
      <div>{post.content}</div>
      <section>
        {comments.map(c => <p key={c.id}>{c.text}</p>)}
      </section>
    </article>
  );
}

Common third-party services for dynamic JAMstack features: Disqus or Utterances for comments, Formspree or Netlify Forms for contact forms, Algolia for search, Auth0 or Supabase for authenticationWhat is authentication?Verifying who a user is, typically through credentials like a password or token..

06

Incremental Static RegenerationWhat is isr?Incremental Static Regeneration - a feature that rebuilds individual static pages in the background after a set time, giving you CDN speed with reasonably fresh data.

Re-building your entire site every time a blog post changes is impractical for large sites. ISR lets Next.js re-generate only the pages that have changed, in the background, after deployment.

export async function getStaticProps() {
  const data = await fetchData();
  return {
    props: { data },
    revalidate: 60 // Re-generate this page after 60 seconds if requested
  };
}
ISR gives you static performance for the vast majority of visitors while keeping content reasonably fresh. The first visitor after the revalidation window triggers the re-generation; everyone after gets the new version.
07

When JAMstack fits and when it doesn't

Good fitPoor fit
Blogs and documentationSocial networks with per-user feeds
Marketing and landing pagesReal-time collaborative tools
Portfolios and company sitesApps that update data thousands of times per day
E-commerce product pagesHighly personalized per-user content
Developer docsComplex form-heavy internal apps
javascript
// JAMstack Example: Blog with Next.js

// pages/index.js
export async function getStaticProps() {
  // Runs at BUILD time (not request time)
  const posts = await fetch('https://api.example.com/posts')
    .then(r => r.json());

  return {
    props: { posts },
    revalidate: 3600 // ISR: Regenerate every hour
  };
}

export default function Home({ posts }) {
  return (
    <div>
      <h1>My Blog</h1>
      {posts.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  );
}

// pages/blog/[slug].js
export async function getStaticPaths() {
  // Tell Next.js which pages to pre-build
  const posts = await fetch('https://api.example.com/posts')
    .then(r => r.json());

  const paths = posts.map(post => ({
    params: { slug: post.slug }
  }));

  return { paths, fallback: 'blocking' };
}

export async function getStaticProps({ params }) {
  const post = await fetch(`https://api.example.com/posts/${params.slug}`)
    .then(r => r.json());

  return { props: { post } };
}

export default function BlogPost({ post }) {
  const [comments, setComments] = useState([]);

  // Dynamic comments (client-side)
  useEffect(() => {
    fetch(`/api/comments?post=${post.id}`)
      .then(r => r.json())
      .then(setComments);
  }, [post.id]);

  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />

      <section>
        <h2>Comments</h2>
        {comments.map(c => (
          <div key={c.id}>{c.text}</div>
        ))}
      </section>
    </article>
  );
}

// pages/api/comments.js (Serverless function)
export default async function handler(req, res) {
  const postId = req.query.post;
  const comments = await database.comments.find({ postId });
  res.json(comments);
}

// Deploy:
// 1. git push
// 2. Vercel auto-builds and deploys
// 3. Site live on CDN worldwide!