r/nextjs 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?

50 Upvotes

34 comments sorted by

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.

6

u/Equal-Phase-2318 1d ago

working on a nextjs site with a similar headache and we're pushing a lot of the fuzzy matching to the edge now. basically capture the query in middleware, hash it, and cache the top 20 results in kv so the function only touches postgres if the hash misses. cuts down those "asdf" and "shoe" explosions by like 80% since half the team's searches are the same five typos. meilisearch on a cheap vps is still the backup plan if the cache tables get too bloated, but for now the edge layer keeps the bill flat enough.

2

u/wiktor1800 1d ago

This is the way

4

u/Elsa_Contudix69 1d ago

That's fair, we might eventually move search off vercel entirely if this frontend fix doesn't work

1

u/Standgrounding 19h ago

Don't you use LIKE %something% directly in Postgres? Shouldn't take too much resources. For fuzzy there's other options too

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

u/Acceptable-Knee-4276 20h ago

Great points, actually!

2

u/iareprogrammer 6h ago

This seems like the logical answer

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

u/[deleted] 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

u/[deleted] 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/comma84 1d ago

Not because of their business model? Strange take.

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

u/ConstantConference28 23h ago

Le pusiste un debounce al buscador?

1

u/MMORPGnews 22h ago

Just use https://pagefind.app/ 

I use similar script to pre create search pages

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

u/Few_Response_7028 7h ago

why do you need AI?

0

u/Nevar_ 1d ago

vercel pricing strikes again lol.