Why Not Just Query Entities Directly
The case for Search API over an entity query or a hand-rolled SQL LIKE clause comes down to a few recurring needs that Drupal's core entity API isn't designed to handle:
- Relevance ranking. Search results should be ordered by how well they match, not just whether they match at all, something EntityQuery has no concept of.
- Tokenized, fuzzy matching. Editors and visitors expect to find "running" when they type "run," and to match across word boundaries rather than requiring an exact substring.
- Cross-entity, cross-bundle search. A single search box often needs to span multiple content types, and sometimes multiple entity types (nodes, users, taxonomy terms) at once, which is awkward to express as a single entity query.
- Backend flexibility. A small site runs fine on a database-backed index; a larger one may need Solr or Elasticsearch for speed and language-aware analysis. Search API lets that decision be revisited later without redesigning the search page.
Core Concepts
Search API organizes everything around a small number of config entities that are worth understanding before touching the admin UI:
- Server (search_api.server.*): represents a connection to a backend, such as the database, a Solr core, or an Elasticsearch cluster. Backend-specific settings (connection details, credentials) live here.
- Index (search_api.index.*): defines what gets searched. An index is attached to a server and specifies which Drupal entities ("datasources") get indexed, which of their fields are searchable, and how those fields are processed.
- Datasource: the source of the indexed content, almost always entity:node, but any entity type (entity:user, entity:taxonomy_term) or a custom datasource plugin can be indexed.
- Processors: pluggable index-time and query-time steps, such as stripping HTML tags from body fields, tokenizing for a given language, boosting a field's relevance weight, or excluding unpublished nodes from the index entirely.
Setting Up a Server and Index
Standing up search with Search API on a Drupal site generally follows this sequence:
- Pull in the module via Composer: composer require drupal/search_api, plus a backend module such as drupal/search_api_solr if the database backend won't be enough at scale.
- Create a server at /admin/config/search/search-api, choosing the backend and its connection settings.
- Create an index, attaching it to that server and selecting the datasource (typically entity:node, restricted to specific content types if needed).
- Add fields to the index: title, body, and any custom fields, including entity-reference fields reached via a property path like field_tags:entity:name, and set each field's type (fulltext, string, integer, date) and relevance boost.
- Configure processors, such as "HTML Filter," "Tokenizer," and "Ignore Case."
- Index the content, either immediately (index_directly enabled) or on cron, and keep this configuration in config/sync/ like any other Drupal config, exported with drush config:export and re-imported with drush config:import.
A field definition inside an index's exported YAML might set title as a text field with a boost of 2.0. That boost value tells Search API's ranking that a match in the title should count for more than an equivalent match in the body, a small, config-only lever for tuning relevance.
Exposing Search Through Views
Once an index exists and is populated, the standard way to expose it on a Drupal site is through Views: a view's base table can be set to a Search API index, with exposed filters for keyword search and faceting on other indexed fields (category, date, content type). This produces a working /search page built almost entirely through Views UI configuration rather than custom controllers.
Autocomplete is a frequent companion, usually added via the search_api_autocomplete contrib module, which suggests matches from the same index as a visitor types. It's worth testing against real content early; duplicate node titles, for instance, can produce confusingly repeated suggestions unless explicitly deduplicated.
Performance and Caching Considerations
Search queries, especially fulltext ones, are meaningfully more expensive than a cached page render, so caching deserves deliberate attention:
- Choose a Views cache plugin that matches the backend: for the database backend, a tag-based plugin (invalidating on relevant entity changes) is usually safe; for an externally, asynchronously indexed backend like Solr, a time-based plugin is the more honest choice.
- Watch for a common trap: a block or render array that hardcodes max-age: 0 will silently force the whole wrapping page render to be uncacheable, even when nothing else on the page needs that.
- If indexing runs on cron rather than immediately on save, that lag is a real, editor-visible constraint (a newly published node won't appear in search until the next indexing run), and it should shape both caching decisions and expectations set with content editors.
Conclusion
Search API earns its complexity by cleanly separating "which backend does the searching" from "which Drupal entities are searchable and how," which keeps a site's search feature adaptable as its scale and requirements change. Getting a first version running is largely a matter of configuration: define a server, build an index over the right entities and fields, expose it through Views, and layer autocomplete on top.
The harder, more valuable work comes after that first pass: tuning relevance boosts, choosing a caching strategy suited to the backend, and testing against real content for edge cases like duplicate labels or entity-reference fields that silently fail to index. Treating those as part of the initial build, rather than problems to defer, is what separates a Drupal search feature that merely works from one that actually serves editors and visitors well.