How I Stopped Letting Neon Eat My Compute For Breakfast 😅
I logged into my Neon dashboard one morning and saw my compute hours climbing in a way that made zero sense for my setup. This was my personal Nextjs site and a small internal tool, not some crazy high traffic product.
I already knew at some point I would need to upgrade, but the timing felt wrong. The usage pattern looked like a busy production app even when I was barely sending people to the site. So I spent a week untangling what was actually happening.
It turned out to be a mix of two things:
• architectural decisions that kept the database awake all day
• background polling that never went to sleep
This is the story and the changes that actually helped, without pretending I magically got compute down to zero. I did end up upgrading. I just stopped paying for nonsense.
First lesson: Compute hours are about time awake, not how fancy your queries are ⏱️
Neon bills you based on how long your compute stays active.
Very simplified:
• every time your app touches the database, a timer resets
• Neon keeps compute alive for a bit after that query
• if you keep hitting the database often enough, the timer never runs out
So you can have a tiny project with modest traffic and still burn through hours if something keeps poking the database in the background. That was me.
Mistake one: Letting development traffic hit production
My first mistake was extremely boring. My development work and experiments were talking directly to the production database.
Every time I ran the dev server, refreshed a page, or tested something, I was burning the same compute pool that was supposed to be for real users. No big surprise that the graph looked chaotic.
Once I pointed my dev environment at its own database and kept production separate, a big chunk of "mystery" usage disappeared. It did not fix everything, but it stopped me from paying for my own experiments.
Mistake two: Treating every request like it needed fresh data
Nextjs is very happy to hit your database on every request if you let it. I had pages and api routes that felt simple, but behind the scenes they were asking Neon for data every single time someone landed on them or refreshed.
The fix here was more mindset than anything:
• ask what actually needs to be real time
• let everything else be cached for a few minutes
• use the built in data cache and incremental static regeneration instead of doing everything live
Once I started caching obvious things like homepage content, lists of posts, and some read only dashboards, most visitors stopped touching the database at all. They were getting cached responses and Neon only woke up when the cache needed a refresh.
Mistake three: Client components that refetched on every mount
I also had patterns where a client component would fetch data as soon as it mounted. That means every navigation that remounts that component turns into a fresh call.
For parts of the site that rarely change, it made more sense to move that logic into server components and let Nextjs handle data fetching at the framework level. That change is not glamorous, but it adds up.
The shift was simple:
• use server components by default for read heavy sections
• reserve client components for truly interactive stuff
• lean on caching and regeneration instead of doing "live" queries everywhere
Mistake four: Background work that never stopped working 🧯
Once I cleaned up the obvious things, the Neon metrics still showed activity at times when nobody should have been using the app. That is when I started looking at my background processes.
This is what I found:
• autosave was running on a very aggressive schedule
• analytics polling happened every few seconds or minutes
• none of those checks respected whether the browser tab was actually in front of the user
• some of the queries themselves were heavier than they needed to be
• there was no caching at all on those metrics
So even if traffic was low, the app was quietly talking to Neon over and over again just to confirm that nothing had changed.
Here is how I untangled that part:
One: I extended the autosave interval and added a proper "only save when the user actually stops typing" behavior. People could still manually save whenever they wanted. I just stopped the app from asking the database if life had changed every few seconds.
Two: I added tab visibility checks so polling paused when the tab was not active. People keep tabs open while they live in email and chat all day. There is no reason to keep hitting the database while your app is sitting behind five other windows.
Three: I cached analytics and dashboard stats for a short window. Most people glance at a dashboard, get a feel for things, then move on. Ten minutes of cache for those numbers was more than enough.
Four: I relaxed the polling schedules themselves. Analytics did not need to update every few seconds to feel responsive. Slower polling plus caching felt the same to the user and cost less compute.
This is also where I fixed some of the "unoptimized count on a large table" patterns and added indexes in the obvious places. Nothing fancy. Just "do not scan the entire table every time you want a simple number".
Mistake five: A sitemap that behaved like a full report 📊
My sitemap was also quietly expensive. I was hitting multiple tables every single time a crawler asked for it. Search engines are polite but persistent.
The fix here was to treat the sitemap more like a static artifact:
• combine all the queries into one place
• generate the data on a schedule instead of on every request
• let search engines read from that cached snapshot
After that, crawler traffic stopped translating into a flood of pointless database queries.
So what actually changed
After all of this, a few things were true at the same time:
• compute hours dropped a lot compared to where I started
• the app actually felt faster because more responses came from cache
• Neon finally had real idle time so compute could suspend between bursts
• I still upgraded my Neon plan, but now the spend made sense for what the app was doing
I did not "hack" Neon or find some magic trick that makes compute free. I just stopped paying for noise.
If your Neon usage does not match what you think your traffic looks like, start with three questions:
• is your dev work sharing the same database as production
• are you caching read heavy routes and pages for at least a few minutes
• is anything in your app quietly polling the database all day in the background
My experience is that once you clean those up, the graph starts to look a lot more like reality and a lot less like panic. And you can decide to upgrade from a calm place instead of a surprise bill. ✨
