Four Places for Logic on a Jamstack Site

One of the first mental hurdles in Jamstack development is understanding that logic isn’t confined to a single layer. A site can execute code at several distinct points in its lifecycle, and the choice of where to run that logic matters for freshness, performance, and maintenance. A date-sensitive feature—like the event list on a music venue’s website—makes the trade-offs clear.

Edit Time: Hand-Written HTML

The most direct approach is to write the HTML yourself, with each event already marked as “upcoming” or “past” based on your own judgment at the moment of authoring. You commit the file, deploy it, and the site is correct until reality changes.

<h1>Upcoming Event: Bill's Banjo Night</h1>
<h1>Past Event: 70s Classics with Jill</h1>

That last caveat is the killer. The moment Bill’s Banjo Night ends, the page is wrong until you open your editor, flip the label, and redeploy. For a site with any amount of churn, this is unsustainable.

Build Time: Structured Data Plus Static Generation

Moving event details into structured data—a Markdown file per event, a headless CMS, or any other data source—enables logic at build time. A static site generator such as Eleventy reads the data and executes whatever logic you want while producing the final HTML. You can run math, call APIs, or compare dates during the build.

---
title: Bill's Banjo Night
date: 2020-09-02
---

The event description goes here!

A template can inspect each event’s date and render different markup accordingly:

{% if event.date > now %}
  <h1>Upcoming Event: {{event.title}}</h1>
{% else %}
  <h1>Past Event: {{event.title}}</h1>
{% endif %}

The problem is that now means “the moment the build runs.” Once those HTML files are uploaded, they don’t change until the next build. An event that started ten minutes ago is still labeled “upcoming” if the build happened before it began.

Automating rebuilds on a schedule helps. The CSS-Tricks conferences site, for instance, uses Zapier to trigger a rebuild daily or even hourly:

The conferences site is deployed daily using a Zapier automation that triggers a Netlify deploy,, ensuring information is current.

But scheduled rebuilds cost build minutes on services like Netlify and can still serve a stale version in edge cases.

Edge Time: Workers at the CDN

Edge workers run code at the CDN level on every request. They weren’t widely available at publication time, but their promise is the ability to run server-side logic while retaining CDN performance:

// THIS DOES NOT WORK
import eventsList from "./eventsList.json"
function onRequest(request) {
  const now = new Date();
  eventList.forEach(event => {
    if (event.date > now) {
      event.upcoming = true;
    }
  })
  const props = {
    events: events,
  }
  request.respondWith(200, render(props), {})
}

Here, render() takes the processed event list and injects it into a pre-rendered template. Because the worker executes per request, every visitor gets a current version of the site, with no waiting on the last build.

Run Time: Logic in the Browser

The final option is to pass structured data to the front end—for instance, embedding it in data attributes—and let JavaScript handle the logic on the user’s device:

<h1>{{event.title}}</h1>

After the page loads, the comparison runs client-side:

function processEvents(){
  const now = new Date()
  events.forEach(event => {
    const eventDate = new Date(event.getAttribute('data-date'))
    if (eventDate > now){
        event.classList.add('upcoming')
    } else {
        event.classList.add('past')
    }
  })
}

Here, now reflects the user’s own clock, which keeps the list current. Because the code is running on the device, you can also localize how dates are displayed or even re-run processEvents() every few seconds—handy for a billboard outside the venue, though probably overkill for a typical website.

Choosing Your Lifecycle Stage

Jamstack’s core idea is to do as much work as possible at build time and serve static HTML. Still, each of the four stages is a legitimate home for logic:

  • Edit time is fine for content that almost never changes.
  • Build time makes sense when you need structured data and can stomach occasional rebuilds.
  • The edge is the right fit for time-sensitive or user-dependent logic that still benefits from CDN speed.
  • Run time is the place for anything that must react to the user’s environment or keep updating while the page is open.

When you find yourself repeatedly flipping a label by hand, it’s a signal to move that logic down the lifecycle.