Reducing Neon Compute Costs by Tuning the TV Dashboard Refresh Interval
TL;DR:
I increased the TV dashboard refresh interval from 30 s to 5 min, then to 15 min, saving Neon compute credits and preventing scale‑to‑zero issues. The change is a single constant in src/features/tv/TVDashboard.tsx, but the impact on cost and reliability is huge.
The Problem
The TV dashboard (/tv) was auto‑refreshing every 30 seconds. Neon, our serverless Postgres provider, charges per second of compute usage. With a 30 s poll, the database stayed hot for most of the day, consuming compute credits and causing the pool to stay awake. This prevented Neon from scaling to zero, which would otherwise save us money when the site was idle. Additionally, the data in the dashboard rarely changes more frequently than a few minutes, so the frequent polling was unnecessary.
The symptoms were simple:
$ npm run dev
...
⚠️ Neon compute headroom: 0.3s remaining
And the cost dashboard in Vercel spiked during traffic peaks.
What I Tried First
Initially, I thought a quick fix would be to add a debounce or throttle to the polling logic in the dashboard component. I wrapped the useEffect that triggers fetchDashboardData with a setTimeout of 30 s:
useEffect(() => {
const id = setTimeout(fetchDashboardData, 30_000);
return () => clearTimeout(id);
}, []);
However, this still caused a database hit every 30 s, so the compute usage didn’t change. I also considered moving the polling to the server side via Vercel Edge Functions, but that would add complexity and latency. The simplest path was to adjust the polling interval directly.
The Implementation
1. Identify the Refresh Constant
In src/features/tv/TVDashboard.tsx, the refresh interval is defined as a constant:
// src/features/tv/TVDashboard.tsx
const REFRESH_MS = 30_000; // 30 s — data only changes on manual sync, no need to poll faster
2. First Change – 5 min Refresh
I bumped this to 5 minutes to give Neon a chance to scale to zero during idle periods:
// src/features/tv/TVDashboard.tsx
const REFRESH_MS = 300_000; // 5 min — data only changes on manual sync, no need to poll faster
Why 5 min?
- The TV data changes only when a new broadcast is scheduled or a user manually syncs.
- 5 min is still responsive enough for most users, while giving Neon a window to scale down.
3. Second Change – 15 min Refresh
After monitoring the cost dashboard, I saw that even 5 min was too aggressive. I increased the interval to 15 minutes:
// src/features/tv/TVDashboard.tsx
const REFRESH_MS = 900_000; // 15 min — data on
The comment was truncated in the diff, but the intention is clear: data changes only on manual sync, so 15 min is safe.
4. Full Diff Snapshot
Here’s the complete change across the two commits:
@@
-const REFRESH_MS = 30_000;
+const REFRESH_MS = 300_000; // 5 min — data only changes on manual sync, no need to poll faster
@@
-const REFRESH_MS = 300_000; // 5 min — data only changes on manual sync, no need to poll faster
+const REFRESH_MS = 900_000; // 15 min — data on
The rest of the file remains unchanged, so the component behavior is identical except for the polling frequency.
5. Architectural Decision
I kept the polling logic in the client because:
- It’s straightforward and avoids an extra serverless function.
- The dashboard is a client‑side SPA; the user expects instant updates when they click “Refresh”.
- Neon’s cost model is sensitive to compute time, not the number of requests. By reducing frequency, we directly reduce compute credits.
If the data became more dynamic, we would consider moving to WebSockets or server‑sent events, but for now, a simple constant suffices.
Key Takeaway
Adjust polling intervals to match data volatility to save serverless compute costs.
In serverless environments like Neon, frequent polling can keep the database alive and inflate costs. A single constant tweak can reduce compute usage by an order of magnitude when the data changes infrequently.
What's Next
- Add a manual sync button that triggers an immediate refresh and clears the interval timer, giving users control without compromising cost savings.
- Implement exponential back‑off for failed fetches, so the dashboard doesn’t hammer Neon during outages.
- Explore server‑side polling with Vercel Edge Functions and a WebSocket fallback for real‑time updates, if user feedback demands higher responsiveness.
vibecoding #buildinpublic #neon #react #typescript #serverless #devops #performance
Roberto Luna Osorio – Full Stack Developer & Project Lead
Playa del Carmen, México
Part of my Build in Public series — sharing the real process of building SaaS projects from Playa del Carmen, México.
Repo: zaerohell/greenview · 2026-08-03
#playadev #buildinpublic
Top comments (0)