Introduction
Entering an expiration date doesn't make a page disappear by itself. Something still has to watch whether the deadline has arrived and unpublish the page when it has. That watching job goes to Vercel Cron (a scheduled-execution mechanism that automatically runs a process at a time you set).
This article covers how the scheduled job finds expired pages and takes them out of view, and what you should return when someone lands on one that has already expired. Behind the experience of content that disappears on its own, there is some quiet but important processing. Since these choices feed straight into how the site is operated, let's start with how the frequency was decided.
Designing the Job That Watches Deadlines
Why once a day is enough
The expiration check runs once a day. Campaign and event deadlines are nearly always day-level — "valid through this date" — and there is almost never a case that demands minute-level accuracy. The configuration is just a request to run this process at a fixed time every day.
Raise the frequency and you raise the number of runs, the effort of confirming it's still working, and the cost. Picking a cadence that isn't excessive for the requirement is part of keeping the system light. For the rare content that must stop the second it expires, setting a lifespan at save time and letting it auto-delete covers that case alongside.
Once a day, at the configured time, the expiration process is invoked automatically
It pulls the list of stored content and compares each expiration date against the current time
Anything past its deadline has its publish flag lowered; anything meant to go is deleted outright
What was retired, and when, is logged so it can be traced later
The flow in one sentence: every day at a set time it compares every record, stops publishing the ones past their deadline, and leaves a record of what it did.
Detecting expiry is just comparing two datetimes
The detection itself is almost anticlimactic. Take each stored page's expiration date and compare it against the current time. If the deadline is in the past, it has expired. That's all. Because the expiration lives inside the data, the rule stays in one place.
To pull the list, the job uses the index of slugs prepared on the storage side. It walks every record, but the number of temporary pages is modest, so speed is a non-issue. Skipping clever optimizations means anyone reading the code later can still tell what it does.
Make sure repeated runs produce the same result
One thing worth being careful about when writing scheduled processing is making sure that running the same process any number of times gives the same result. The technical term is idempotency, though the name isn't the part you need to remember.
Scheduled jobs occasionally fire twice, or fail partway and get retried automatically. When that happens, re-retiring something already retired must not cause anything strange. "If past the deadline, stop publishing" is naturally unchanged by repetition, so it already satisfies this. Keep that property intact and you can design retries and error handling without worrying.
What to Show Users After Expiry
Return a 404, or show a notice?
When someone opens an expired page, there are broadly two choices. Return a 404 (the response meaning the page doesn't exist), or show a notice reading "this page is no longer available." Which one fits depends on the nature of the content.
For a purely disposable internal URL, a 404 is plenty. But for something like a campaign page that spread on social media and still gets clicked in good faith, a notice is the kinder answer. Rather than assuming expiry means an immediate 404, decide how the page ends and you'll spare people some needless confusion.
The table's point: whether the URL has circulated outside your organization is what changes the right answer.
Check the expiration again on every render
Because the job runs once a day, a gap opens between the moment a deadline passes and the next run. To keep a stale page from showing during that window, the public page also checks the expiration every time it renders.
Right after fetching the record, it compares the deadline to the current time and, if it has passed, treats the page as expired on the spot. The scheduled job is the one that clears things out in batches; the render-time check is the one that decides on the spot. Adding that second layer means the timing of expiry has no holes in it.
Combine "expires on a deadline" with "only some people can see it"
Some temporary pages need their audience narrowed in the first place — documents handed to a single business partner, or something shared internally for a short period. In those cases, on top of expiring by deadline, you control access itself: a slug that's hard to guess, or a simple viewing restriction.
Expiring on a deadline and restricting who can view are separate mechanisms. Combined, though, they widen the range of situations you can cover. Build it so that both cases — already expired, and not yet published — fail toward the safe side, and you can stop worrying about either.
Mind the gap in between
Relying on the schedule alone leaves a window between the deadline passing and the next run, and a stale page can show during it. Always add the render-time expiration check so nothing slips through.
Summary
Cron-based auto-expiration takes the simple job of watching deadlines and unpublishing, and does it every day in place of a person. The parts to get right: a once-a-day cadence matched to the requirement, processing that repeats safely, and the render-time double check. With those three in place, stale pages essentially stop appearing.
The other thing worth settling in advance is what expired pages show. Cut it off with a 404, or show a notice pointing to where to go next. Deciding that far means users who arrive after the fact aren't left with nothing.
How the data this job watches is stored, and where the whole mechanism actually earns its keep, are covered in the next articles.
Managing Temporary Content with KV Storage
How the data the scheduled job watches is stored and shaped.
Use Cases for Disposable URLs
Concrete patterns where the auto-expiration mechanism pays off.
Auto-Expiring Content — Designing Away "Forgot to Take It Down"
The hub article covering the big picture and the thinking behind the design.