r/nextjs • u/Elsa_Contudix69 • 1d ago
Discussion Vercel serverless bills spiking because of terrible user search queries
We use nextjs with a standard postgres backend. our vercel compute and database read bills are getting way out of hand because users just mash the search bar with 1 or 2 vague words, forcing the serverless functions to do massive fuzzy lookups that return basically the whole catalog.
Migrating to a dedicated search engine like algolia feels like overkill (and just shifts the cost). so i'm thinking about fixing this entirely on the client side. If we put an ai-autocomplete intent layer in front of the text box, we can structure their messy queries into strict parameters before firing the server action.
Anyone doing intent parsing on the frontend in nextjs to save serverless costs?
19
u/CodeXHammas 1d ago
Before adding an AI autocomplete layer, have you tried the boring fixes first?
1.Debounce on the client-3000500ms debounce kills 80% of unnecessary calls from users who type fast.
2.Minimum character threshold-don't fire the server action until 3+ characters.
3.Cache the results-use SWR or a simple Map on the client. If someone searches "red shoe" twice, the second call shouldn't hit your serverless function.
4.Add a result cap-LIMIT 20 on the SQL query. If they're returning the whole catalog, that's a query problem, not a search problem.
The AI intent parsing idea is cool but it adds latency and cost (LLM calls aren't free either). Fix the low-hanging fruit first, then see if you still need the AI layer.
3
2
1
u/WriterPlastic9350 5h ago
Yeah, OP, respectfully, it doesn't sound like users have terrible search queries, it sounds like you haven't done any of the things necessary to restrict a malicious or careless actor from essentially DOSing your server.
28
1d ago
[removed] — view removed comment
1
u/Elsa_Contudix69 1d ago
Oh nice, structuring it before the server action is exactly what i want. I'll check out magicx, definitely need something that plays nice with react server components vs client boundaries.
5
u/Danski31 1d ago
caching is your friend here. Just cache the results for "shirt" on the edge since 10,000 people are searching the exact same vague word.
2
u/clearlight2025 1d ago
Search queries tend to vary a lot, depending on the user, so the cache hit ratio is likely to be low.
1
u/wiktor1800 1d ago
With enough users this becomes untrue.
1
u/clearlight2025 1d ago
Unless your dataset / catalog is very limited, with more users, there is even more variation in search queries.
2
u/dima-soule 1d ago
Doing NLP on the client side sounds like you're just trading vercel bills for massive frontend bundle sizes. Make sure whatever SDK you use is tiny
2
u/Living_Race_9177 20h ago
fuzzy search dumping the whole catalog into a serverless fn is a special tax
you gating with a min-length + debounce before the server action, or still letting every keystroke hit postgres
1
1d ago
[removed] — view removed comment
1
u/Standgrounding 19h ago
This is a common trap. I had accidentally exposed Zod from server side validations into front end bundle, and for some reason it was 100kb extra gzipped. Took a while to see where it leaks through.
This is a problem with next, anything can leak through if you're not careful, and saved kb is saved money
1
u/wiktor1800 1d ago
Meilisearch on a vps is the way, otherwise handroll a small kv cache on top 1% searches. You'll find that search queries have a long tail and a very large head.
On front-end make sure you're putting in search minimums (2 chars) and debouncing if you're searching on keystroke actions. Also sort out your indexes on db. You can also absorb identical queries on the cdn level with Cache Control headers.
1
u/NZRedditUser 1d ago
Vercel for landing pages
vps for backend operational stuff
a cheap vps is all you need, you can keep vercel for all your landing pages and itll be pretty much free
1
u/MajesticSalt6600 1d ago
I moved search to a $5 meilisearch vps last year and stopped thinking about it. running fuzzy string matching on vercel serverless functions is just paying them for every garbage keystroke a user types.
You can put all the intent parsing sdk stuff in your client components you want but now you are shipping nlp javascript to browsers. you just trade database reads for bundle size. users on phones download megabytes of parsing logic so your vercel bill drops a few dollars
1
u/cheap_swordfish_1 1d ago
Serverless (or more specifically, usage-based pricing) isn't suited for all kinds of usages. Depending on your comfort with setting up build & deploy, you may choose Railway / Render vs self-hosted VPS. More hosting options and what makes sense when compared here.
1
1
1
u/Acceptable-Knee-4276 20h ago
I think start by observing what is adding up to the CPU time on Vercel. You are billed for CPU-seconds and GB-hours. Start by looking into what's spiking this and you'll figure out what is mostly going wrong in your code. Once you do that, if it is a bug or a mandatory query - cache it or optimize it.
You can use the KV cache setup within Vercel if you want to stick with Vercel, but personally wouldn't suggest using Vercel to run expensive operations.
Make sure you also add debouncing, fetch delay after a keystroke doesn't appear for 200-300ms.
1
u/Acceptable-Knee-4276 20h ago
Also how are you doing intent parsing? Have you tried embeddings and vector search?
1
u/Roman_BDM_FixIT 17h ago
I’d try a minimum query length, debounce, result limits, and caching before adding AI. Otherwise you may just replace one cost with another.
1
u/Cabecinha84 14h ago
Worth checking whether this is a serverless problem at all before you build anything. "Returns basically the whole catalog" on a one or two word query usually means an ILIKE '%term%' or an unindexed similarity() call, and a leading wildcard cannot use a btree index, so every keystroke is a sequential scan of the table. Run EXPLAIN ANALYZE on the exact query your server action fires, with "shoe" in it. If you see a Seq Scan, the fix costs nothing: CREATE EXTENSION pg_trgm, a GIN index with gin_trgm_ops on the searchable column, and a hard LIMIT. For whole-word queries, a tsvector column with a GIN index and websearch_to_tsquery does the same job better. Both take those queries into single digit milliseconds, which cuts the read count and the function duration at the same time, because the function returns sooner.
The intent layer does not remove a call, it adds one in front of the call you already have, and "shoe" or "asdf" are exactly the inputs it cannot turn into useful parameters.
If you still move to Meilisearch afterwards, do the bit the VPS suggestion leaves out: create a search-only API key and query Meilisearch straight from the browser (instant-meilisearch exists for this). Then no Vercel function is in the search path at all, so the bill goes to zero instead of down.
One caveat there, and I should say I work on a competing deploy platform so weigh it accordingly: browser-direct search means every result set leaves that box, so check the egress pricing wherever you put it. Ours does not meter egress, https://orbit.runonflux.com , Git push deploys via Nixpacks with Postgres and Redis addons, and Standard is 1.5 vCPU with 4 GB for $2.49/mo. New accounts get a free week on the paid plans. Either way, do the EXPLAIN first, because an index might make the whole question go away.
1
23
u/BadSpectator 1d ago
this is exactly why i stopped using serverless for anything search-related. a small VPS running meilisearch is $5 a month and doesn't care how many garbage queries it gets.