What this post covers
While adding full-text search to a serverless-deployed site, I sorted out "what can live inside the function and what has to live outside." The key is the difference between a process that must always be up (like Elasticsearch) and a function that wakes up per request.
1. Serverless search backend and async search UI
Background (concepts)
- Serverless function: a stateless environment that runs and terminates per request. You can't just host a memory-resident daemon on it.
- Inverted index: word → list of document ids. It can be built at build time and read from the function.
- Out-of-order response: a UI bug where a slow earlier request arrives late and overwrites the latest result.
What the situation was
A serverless-deployed site needed search. You can't just spin up a resident search-engine process inside the function. To deploy without external hosting, I needed a library-style index that runs in function memory.
Since the client hits the search API on every keystroke, the UI can get out of sync without debounce, cancellation, and latest-request priority.
There were four goals — an in-memory inverted index that runs inside serverless (search backend), the build-artifact index file being included even on cold start (deployment stability), the UI and tests seeing only a provider contract so a resident engine can be swapped in later (swappability), and only the latest result reflected on screen (search UI).
Core work
- Index: read the pre-built file from the function and searched it as an in-memory inverted index.
- Bundle: solved cold-start omission by declaring the runtime-read build artifact in the bundle-tracing config. (The blocker — the index file wasn't found on cold start → resolved by explicitly including the build artifact in the function bundle.)
- Contract: made the client depend only on the search provider contract and a single API endpoint, so the UI and tests stay put even if a resident engine replaces it later.
- UI: applied the debounce, AbortController, and latest-request-id patterns.
Takeaways
- The boundary between resident vs. library-style search is "does it have to stay resident in memory."
- An async search UI must use debounce, cancellation, and a latest-request id together.
- Content metadata is more consistent when decided at build time from a single source than from a runtime DB.
- Follow-up: define the criteria for switching to a resident engine at the point Korean search quality becomes necessary.
→ Serverless stateless execution · Inverted index full-text search · Race-safe async UI requests · Single source of truth content metadata