No search results: which HTTP status code should you use?

Use 200 OK and return an empty collection when a valid search completes with no matches. For a JSON API, that normally means [] or a stable response object such as { "items": [], "total": 0 }.
Use 404 Not Found when the resource or endpoint itself does not exist. Use 204 No Content only when deliberately returning no response body. For search endpoints, a consistent response shape is usually easier for clients to consume.
The scenario
Say we are searching some rest api for results GET /api/collection?filter=value&filter=value. What should the API return if there are no results?
The recommendation follows the current HTTP semantics: a successful GET with 200 OK carries a representation of the target resource, while a 204 response has no content. The API-design choice is how you represent an empty collection.
404 Not Found
Not Found sounds plausible, but the requested resource in this case is the collection. The collection exists and the query was valid; it simply contains no matching items.
This is valid in the case where a single entity requested by the user doesn't exist. The user asked for a resource that doesn't exist. They should change their request.
But no search results is not a user error (depending on your api of course). No results is an expected response from a collection api like a search filter.
In this endpoint the resource is the collection itself. The collection should exist. Using a 404 could also lead a developer to think that your endpoint/collection doesn't actually exist when in fact it's just that there is no data. This could waste a lot of time.
For an issue where the developer tries to search a collection that doesn't exist. I would return a 404.
204 No Content
No content also sounds like something that might be appropriate. The search was successful but there are no results. This is semantically correct. However the RFC states that
The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields.
That forces a client to handle a different response shape for an ordinary empty result. It is valid HTTP, but less convenient than returning the same collection representation every time.
200 OK
The request succeeded, so return the same shape used when matches exist:
HTTP/1.1 200 OK
Content-Type: application/json
{"items":[],"total":0}
I feel that having a consistent array in the body is easier to work with and since we design APIs to be consumed as easily as possible.
Use a distinct error response only when something actually failed: an invalid filter might be 400, an unauthenticated request 401, and an endpoint or individually addressed record that does not exist 404.
See RFC 9110: HTTP Semantics for the definitions of 200, 204 and 404.