Skip to content

perf: make the login page cacheable, and drop a fact that never rendered - #57

Merged
pataniaeli merged 1 commit into
devfrom
perf/login-page-cacheable
Aug 28, 2026
Merged

perf: make the login page cacheable, and drop a fact that never rendered#57
pataniaeli merged 1 commit into
devfrom
perf/login-page-cacheable

Conversation

@pataniaeli

Copy link
Copy Markdown
Collaborator

The first page every user hits was re-rendering — and re-querying — on every request.

Measured against production: / at 0.48–1.09 s TTFB, versus 0.23–0.39 s for a dashboard redirect. It was the slowest server render in the app, and it's the one nobody gets to skip.

Why it was dynamic

Nothing on the page is per-user: a comptroller's name, the active semester, and a booking count — all readable by anon under RLS.

It was dynamic purely because it built its Supabase client from cookies(), and calling cookies() opts a route into dynamic rendering whether or not the cookies end up mattering. Reading through a cookie-free anon client instead lets the page prerender, with revalidate = 60 regenerating it at most once a minute.

In the build it moves from ƒ / to:

┌ ○ /                        1m      1y

Served locally from the production build, warm TTFB is 8–29 ms, and the response is byte-identical across requests (12393 every time) — previously production varied per request (12586 / 12455 / 12470) because it re-rendered and reshuffled each time.

Reading as anon is also more correct. "Bookings this semester" means all of them, but the cookie client counted only what that visitor's RLS allowed — so a signed-in visitor and a signed-out one saw different numbers for a figure meant to describe the whole organisation.

The fact that never worked

"Active reservations right now" is removed rather than repaired, per your call. Two independent defects:

It filtered on status = 'Confirmed', which exists in none of the three tables it queried. The real vocabulary is Reserved / Tentative / Virtual / Alternate Time / Waitlisted / Unavailable / Cancelled, and 'Confirmed' appears nowhere else in the codebase — it was a phantom, not a drift. Verified against production:

table rows matching 'Confirmed' total
one_time_room_bookings 0 17
weekly_room_occurrences 0 371
tabling_sessions 0 0

So its count was always 0, and the fact is gated on > 0it has never once been displayed.

It also compared Boston booking times against a UTC clock. At the time I checked, the page queried 22:03 while its data means 18:03 — four hours out, and after 8pm Eastern the date rolls to tomorrow entirely, so it looks at the wrong day.

Three queries, on the entry page's critical path, for something that could not render. That halves the page's database work as a side effect: six round trips down to three, two of which run in parallel.

Behaviour change

The displayed fact is picked with Math.random() at render, so it now varies per revalidation window rather than per request. Two people signing in within the same minute see the same piece of trivia. Given it's decorative and a user sees it once per login, that seemed the right trade for the TTFB — but it is a real change, and it's reversible by moving the pick client-side if you'd rather keep per-visitor variety.

Verified

Typecheck and build pass; lint is 3 warnings better than dev. Served the production build locally and confirmed the login form renders, a fact renders, and the dead fact is gone.

The first page every user hits was re-rendering, and re-querying, on every
request -- 0.5-1.1s TTFB measured against production, against 0.23-0.39s for a
dashboard redirect.

Nothing on it is per-user. It is a comptroller's name, the active semester and a
booking count, all readable by `anon` under RLS. It was dynamic only because it
built its Supabase client from cookies(), and calling cookies() opts a route into
dynamic rendering whether or not the cookies end up mattering. Reading through a
cookie-free anon client instead lets the page prerender; `revalidate = 60`
regenerates it at most once a minute. In the build it moves from `f /` to
`o /  1m`, and locally it serves in 8-29ms from cache rather than being rebuilt
per request.

Reading as `anon` is also the more correct reading. "Bookings this semester"
means all of them, but the cookie client counted only what that visitor's RLS
allowed, so a signed-in visitor and a signed-out one saw different numbers for a
figure describing the whole organisation.

The "Active reservations right now" fact is removed rather than repaired. It
filtered on status 'Confirmed', which exists in none of the three tables it
queried -- the real vocabulary is Reserved / Tentative / Virtual / Alternate
Time / Waitlisted / Unavailable / Cancelled, and 'Confirmed' appears nowhere else
in the codebase. Its count was therefore always 0, and the fact is gated on
`> 0`, so it has never once been displayed. It also compared Boston booking
times against a UTC clock, four hours out, and rolled to the wrong day entirely
after 8pm Eastern. Three queries on the entry page's critical path, for
something that could not render.

That halves the page's database work as a side effect: six round trips down to
three, two of which are parallel.

Behaviour change: the displayed fact is picked with Math.random() at render, so
it now varies per revalidation window rather than per request. Two people
signing in within the same minute see the same piece of trivia.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
chambers Ready Ready Preview Aug 28, 2026 10:11pm

@pataniaeli pataniaeli self-assigned this Aug 28, 2026
@pataniaeli
pataniaeli merged commit 0ba4c17 into dev Aug 28, 2026
4 checks passed
@pataniaeli
pataniaeli deleted the perf/login-page-cacheable branch August 28, 2026 22:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant