Skip to main content
โšก Calmops

Jamstack Architecture: Building Fast, Scalable Websites

Introduction

Jamstack is an architecture pattern that decouples the frontend from the backend, enabling pre-rendered static pages combined with dynamic APIs. For startups, this means incredible performance, rock-solid security, and minimal infrastructure costs. This guide covers everything you need to build Jamstack applications.


Understanding Jamstack

The Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                   Jamstack Architecture                      โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                             โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”‚
โ”‚   โ”‚              CDN (Global Edge)                    โ”‚     โ”‚
โ”‚   โ”‚         Static Files + Serverless                 โ”‚     โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ”‚
โ”‚                        โ”‚                                   โ”‚
โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”              โ”‚
โ”‚    โ”‚                  โ”‚                  โ”‚              โ”‚
โ”‚    โ–ผ                  โ–ผ                  โ–ผ              โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”         โ”‚
โ”‚ โ”‚  JS  โ”‚       โ”‚  APIs    โ”‚      โ”‚  CMS    โ”‚         โ”‚
โ”‚ โ”‚ Reactโ”‚       โ”‚ Supabase โ”‚      โ”‚ Contentfulโ”‚         โ”‚
โ”‚ โ”‚ Vue  โ”‚       โ”‚ Stripe   โ”‚      โ”‚ Sanity  โ”‚         โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜         โ”‚
โ”‚                                                             โ”‚
โ”‚   Static + Dynamic = Jamstack                               โ”‚
โ”‚                                                             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Key Benefits

# Why Jamstack works for startups
benefits:
  performance:
    - "Pre-rendered HTML - instant loads"
    - "CDN distribution - global edge"
    - "No server rendering - fast TTFB"
    
  security:
    - "No server to hack"
    - "Static files = attack surface minimized"
    - "APIs isolated"
    
  scalability:
    - "CDN handles any traffic"
    - "No server bottlenecks"
    - "Pay only for CDN usage"
    
  developer_experience:
    - "Git-based workflow"
    - "Preview deployments"
    - "Modern frontend frameworks"

Static Site Generation (SSG)

Next.js Static Export

// app/blog/[slug]/page.tsx
import { getPostBySlug, getAllPostSlugs } from '@/lib/api'

// Generate static pages at build time
export async function generateStaticParams() {
  const posts = await getAllPostSlugs()
  return posts.map((post) => ({ slug: post.slug }))
}

// This page is pre-rendered at build time
export default async function BlogPost({ params }: { params: { slug: string } }) {
  const post = await getPostBySlug(params.slug)
  
  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  )
}

Incremental Static Regeneration (ISR)

// ISR: Update pages without rebuild
export const revalidate = 60 // Revalidate every 60 seconds

// Or with dynamic data
export default async function ProductPage({ params }: { params: { slug: string } }) {
  const product = await fetch(`https://api.example.com/products/${params.slug}`, {
    next: { revalidate: 60 } // Cache for 60 seconds
  }).then(r => r.json())
  
  return <ProductDetails product={product} />
}

Dynamic Content with API Routes

Serverless API Routes

// pages/api/orders.ts
import type { NextApiRequest, NextApiResponse } from 'next'

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' })
  }
  
  try {
    // Verify auth
    const session = await getSession({ req })
    if (!session) {
      return res.status(401).json({ error: 'Unauthorized' })
    }
    
    // Create order in database
    const order = await createOrder({
      userId: session.user.id,
      items: req.body.items,
    })
    
    // Process payment (Stripe)
    await processPayment(order)
    
    res.status(200).json({ orderId: order.id })
  } catch (error) {
    res.status(500).json({ error: 'Failed to create order' })
  }
}

Connecting to External APIs

// Using external APIs in static pages
// app/page.tsx

async function getData() {
  // Fetch at build time (for SSG)
  const res = await fetch('https://api.example.com/data', {
    next: { revalidate: 3600 } // ISR: revalidate every hour
  })
  return res.json()
}

export default async function Page() {
  const data = await getData()
  
  return (
    <main>
      <h1>{data.title}</h1>
      {data.items.map(item => (
        <div key={item.id}>{item.name}</div>
      ))}
    </main>
  )
}

Headless CMS Integration

Contentful Example

// lib/contentful.ts
import { createClient } from 'contentful'

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

// Fetch all blog posts
export async function getBlogPosts() {
  const entries = await client.getEntries({
    content_type: 'blogPost',
    order: ['-sys.createdAt'],
  })
  
  return entries.items.map((entry) => ({
    id: entry.sys.id,
    title: entry.fields.title,
    slug: entry.fields.slug,
    content: entry.fields.content,
    publishDate: entry.fields.publishDate,
  }))
}

// Fetch single post
export async function getBlogPost(slug: string) {
  const entries = await client.getEntries({
    content_type: 'blogPost',
    'fields.slug': slug,
    limit: 1,
  })
  
  if (!entries.items.length) return null
  
  const entry = entries.items[0]
  return {
    id: entry.sys.id,
    title: entry.fields.title,
    slug: entry.fields.slug,
    content: entry.fields.content,
  }
}

Sanity CMS Example

// lib/sanity.ts
import { createClient } from 'next-sanity'

export const client = createClient({
  projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
  dataset: 'production',
  apiVersion: '2024-01-01',
  useCdn: true,
})

// GROQ query
export async function getProducts() {
  return client.fetch(`
    *[_type == "product"] | order(name asc) {
      _id,
      name,
      slug,
      price,
      "imageUrl": image.asset->url
    }
  `)
}

Deployment

Vercel Deployment

# Deploy to Vercel with one command
npm i -g vercel
vercel

# Or connect GitHub - automatic deployments
# Every push triggers a deployment
// vercel.json
{
  "framework": "nextjs",
  "buildCommand": "npm run build",
  "outputDirectory": ".next",
  "rewrites": [
    {
      "source": "/api/(.*)",
      "destination": "/api/$1"
    }
  ]
}

Netlify Deployment

# netlify.toml
[build]
  command = "npm run build"
  publish = ".next"

[[redirects]]
  from = "/api/*"
  to = "/api/:splat"
  status = 200

[[headers]]
  for = "/static/*"
  [headers.values]
    Cache-Control = "public, max-age=31536000, immutable"

Performance Optimization

Image Optimization

// Next.js Image component
import Image from 'next/image'

export default function ProductImage({ src, alt }) {
  return (
    <Image
      src={src}
      alt={alt}
      width={800}
      height={600}
      // Automatic optimization:
      // - WebP/AVIF conversion
      // - Responsive sizes
      // - Lazy loading
      // - Blur placeholder
      placeholder="blur"
      blurDataURL={generateBlurPlaceholder(src)}
    />
  )
}

Script Optimization

// Load third-party scripts efficiently
import Script from 'next/script'

export function Analytics() {
  return (
    <>
      <Script
        src="https://analytics.example.com/script.js"
        strategy="lazyOnload" // Load after page is interactive
      />
      <Script
        id="chat-widget"
        src="https://chat.example.com/widget.js"
        strategy="afterInteractive" // Load after hydration
        onLoad={() => console.log('Chat loaded')}
      />
    </>
  )
}

Cost Analysis

Monthly Costs

# Jamstack hosting costs (2025)
providers:
  vercel:
    free: "100GB bandwidth, 100 hours build"
    pro: "$20/month (unlimited bandwidth)"
    
  netlify:
    free: "100GB bandwidth"
    pro: "$19/month"
    
  cloudflare_pages:
    free: "Unlimited bandwidth!"
    # Truly free for most startups

Example: 100K Monthly Visitors

# Cost breakdown for 100K visitors
scenario:
  page_views: "300K/month"
  avg_page_size: "500KB"
  bandwidth: "150GB/month"
  
vercel_pro: "$20/month"
netlify_pro: "$19/month"  
cloudflare_pages: "$0/month (free)"

Common Pitfalls

1. Too Much Client-Side Rendering

Wrong:

// Fetching everything on client
useEffect(() => {
  fetch('/api/data').then(setData)
}, [])

Correct:

// Fetch at build time or server
export async function getStaticProps() {
  const data = await fetchData()
  return { props: { data } }
}

2. Not Using Edge Functions

Wrong:

// Standard serverless (cold starts)
export default function handler(req, res) {
  // Slow first request
}

Correct:

// Edge function (instant cold start)
export const runtime = 'edge'

export default function handler(req) {
  // Global distribution, instant response
}

Key Takeaways

  • Jamstack = Static + APIs - Best of both worlds
  • Pre-render everything possible - Use SSG/ISR
  • CDN handles scale - Don’t worry about traffic
  • Choose Vercel/Netlify - Great DX and free tiers
  • Use headless CMS - Content management without complexity

External Resources

Platforms

CMS Options

Comments