Model or dataset
matchish/laravel-scout-elasticsearch avatar
matchish/laravel-scout-elasticsearch

laravel-scout-elasticsearch puts a real search engine behind Scout

Search among multiple models with ElasticSearch and Laravel Scout

742 stars125 forksPHPMIT

At a glance

What is it?
matchish/laravel-scout-elasticsearch is a Laravel Scout driver that indexes your Eloquent models into Elasticsearch, and its most useful feature is zero-downtime reimport, so a mapping change in production does not require an outage. The package targets PHP 8 and Laravel 8 or newer, and its Elasticsearch 8 support is still on an alpha branch while the 7.x line is the released one.
Who is it for?
Adopt laravel-scout-elasticsearch if you are on Laravel Scout and need Elasticsearch rather than the default database engine, since the driver gives you the full query surface and a reimport path that does not need an outage.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 15 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

It is a Scout driver, not a search layer of its own

The package provides a starting point to integrate ElasticSearch into a Laravel application, carefully crafted to simplify the usage of ElasticSearch within the Laravel Framework.

It is built on top of the latest release of Laravel Scout, the official Laravel search package. Using this package, you are free to take advantage of all of Laravel Scout's features, and at the same time use the complete set of ElasticSearch's search experience.

That framing matters for the decision. Scout is an abstraction that lets you write `Model::search('query')` and have the engine underneath be Algolia, Meilisearch, Typesense, a database engine or, here, Elasticsearch. If you are already using Scout, adding this driver changes the engine and gives you nothing else, which is exactly the point: the search API in your controllers does not change.

The feature list is mostly about the import pipeline rather than the query side, and that is a good sign about where the work is. It lists Laravel Scout 10.x support, Laravel Nova support, search amongst multiple models, zero downtime reimport, eager load relations to speed up import, parallel import to make the import as fast as possible which is in the alpha version for now, import all searchable models at once, a fully configurable mapping for each model, and the full power of ElasticSearch in your queries.

The requirements are PHP version 8.0 or higher and Laravel Framework version 8.0.0 or higher, and for Laravel Framework below 6.0.0 you use the 3.x branch. The Elasticsearch compatibility table is versioned too: Elasticsearch 8.0 or newer with ElasticsearchDSL 8.0.0 or newer, Elasticsearch 7.0 with DSL 3.0.0 or newer, and Elasticsearch 6.x with a DSL below 3.0.0.

The project is MIT licensed, PHP, with the last push on 2026-10-08 and releases v7.13.0 from 2026-05-09 and 8.0.0 alpha builds in February and May 2026.

Installation is a composer line and three environment variables

The install is a composer require:

bash
composer require matchish/laravel-scout-elasticsearch

Then the driver has to be pointed at in the environment:

code
SCOUT_DRIVER=Matchish\ScoutElasticSearch\Engines\ElasticSearchEngine

The package uses `\ElasticSearch\Client` from the official package, but does not try to configure it beyond connection configuration, so you are free to do it in your app service provider. If you do not want to do it right now, you can use `Matchish\ElasticSearchServiceProvider` from the package, registered in `config/app.php`:

php
'providers' => [
    // Other Service Providers

    \Matchish\ScoutElasticSearch\ElasticSearchServiceProvider::class
],

Then the host, and this is where the multi-node form appears:

code
ELASTICSEARCH_HOST=host:port

or with commas as separator for additional nodes:

code
ELASTICSEARCH_HOST=host:port,host:port

SSL verification can be disabled in your env with `ELASTICSEARCH_SSL_VERIFICATION=false`, and the config example for elasticsearch is published with `php artisan vendor:publish --tag config`.

The design decision in there is the one worth noticing. The package does not own the client, it only consumes one. That means the connection, the authentication and any client middleware stay under your application's control, which is the right boundary for a package that will be running against a production cluster. The cost is that a misconfigured client is your problem rather than the package's.

The environment file in the repository shows the full local setup, with ELASTICSEARCH_HOST as elasticsearch:9200 and the four DB variables pointing at a db service.

Index mappings are a configuration contract, not an afterthought

The indexing section is short but it carries the most consequential warning in the documentation.

It is very important to define the mapping when you create an index, and an inappropriate preliminary definition and mapping may result in the wrong search results.

The mechanism is config keys. If a method `searchableAs` returns the string `products`, the config key for mappings should be `elasticsearch.indices.mappings.products`, and you can specify default mappings with the config key `elasticsearch.indices.mappings.default`. Settings work the same way, with `elasticsearch.indices.settings.products` for an index named products and `elasticsearch.indices.settings.default` for the default.

The per-index and the default keys are both there because a project usually has one model whose mapping you want to hand-tune and several you do not want to think about. The default catches the rest, which is the right default for a code-first workflow where the index name comes from `searchableAs`.

The reason this matters more in Elasticsearch than in most search engines is that a mapping decision is close to irreversible. The type of a field is fixed when the index is created, and a field indexed as text cannot be turned into a keyword later without reindexing. The search results being wrong, rather than the import failing, is the failure mode the warning is pointing at, and it is the kind of problem that surfaces in production rather than in development.

Which is why the zero-downtime reimport feature matters more than it first appears. A mapping that has to be corrected after the fact is a mapping you would rather not have to change, and the reimport path is what makes a change affordable at all.

Eager loading and the import source factory

The import is where most of the time goes, and the package gives you two levers for it.

The first is eager loading. To speed up import you can eager load relations on import using global scopes, and you configure it by binding an `ImportSourceFactory` in your service provider's `register` method:

php
use Matchish\ScoutElasticSearch\Searchable\ImportSourceFactory;
...
public function register(): void
{
$this->app->bind(ImportSourceFactory::class, MyImportSourceFactory::class);

And the factory itself is a class that returns an import source with the scopes you want:

php
namespace Matchish\ScoutElasticSearch\Searchable;

final class MyImportSourceFactory implements ImportSourceFactory
{
    public static function from(string $className): ImportSource
    {
        //Add all required scopes
        return new DefaultImportSource($className, [new WithCommentsScope()]);
    }
}

The pattern is a factory bound in the container, which is the idiomatic Laravel way to make behaviour configurable without editing the package. The comment in the example, add all required scopes, tells you the scope list is where you declare which relations get loaded during the import.

The second lever is the feature called import all searchable models at once, which handles the case where you have a dozen models to index and do not want to trigger each one separately. And parallel import, to make the import as fast as possible, is in the alpha version for now, so it is the one feature here you would treat as a preview.

The combination matters because indexing is the expensive part of adopting Elasticsearch over Scout's database engine. Once your index is populated, queries are fast, but getting a hundred thousand rows in takes as long as the import takes, and the import is a bulk operation against a remote cluster. Eager loading removes the N+1 queries the ORM would otherwise fire per row, and the at-once import avoids serialising model by model.

The local stack is Elasticsearch, MySQL, Cerebro and an Xdebug container

The compose file in the repository shows what the maintainers run in development, and it is a good guide to the production shape.

The application service builds from ./docker/app with a target of php-${APP_ENV}, runs as user 1000:1000, and depends on both elasticsearch and db. It mounts the passwd and group files read-only so the container user maps to a real user, mounts the project at /app, and has a home-dir volume. Xdebug and the IDE config are passed through as environment variables.

The database is mysql:5.7.22, and the elasticsearch service is docker.elastic.co/elasticsearch/elasticsearch:8.1.3, also as user 1000:1000, with a named volume for the data, the password from the environment, single-node discovery, disk threshold allocation disabled, memory lock bootstrapped, destructive actions not requiring a name, and ES_JAVA_OPTS set to a 512 megabyte heap. The memlock ulimit is unlimited in both directions, which is what the memory lock bootstrap check requires.

Cerebro is there as an Elasticsearch admin UI on port 9002 mapped to 9000, which is the quickest way to look at an index mapping or run a query by hand while developing.

Two of those settings are worth understanding if you copy them. The 512 megabyte heap is a development setting and Elasticsearch will be slow with it, while the disk threshold allocation being disabled is a development convenience that you should not carry to production, since it removes the protection that stops Elasticsearch writing itself into a full disk.

The Makefile wraps the compose commands with self-documenting targets, so make up, make down, make shell, make install, make test and make test-coverage are the working day commands. The up target has a Windows-specific branch that raises vm.max_map_count, which is the kernel setting Elasticsearch requires for memory mapping, and that is the kind of detail that otherwise costs an afternoon.

Editorial conclusion

Adopt laravel-scout-elasticsearch if you are on Laravel Scout and need Elasticsearch rather than the default database engine, since the driver gives you the full query surface and a reimport path that does not need an outage. Skip it if your search needs are modest, because Scout's database engine avoids running a search cluster at all, and be careful about the version matrix, since Elasticsearch 8 support is on an alpha branch while the released 7.x line pairs with Elasticsearch 7 and the older DSL. Verify first which Elasticsearch version you run and which driver line matches it, that your index mappings are defined before you create the index, and that you can tolerate a separate cluster to operate.

Frequently asked questions

How do I install and configure laravel-scout-elasticsearch?

Run `composer require matchish/laravel-scout-elasticsearch`, set `SCOUT_DRIVER=Matchish\ScoutElasticSearch\Engines\ElasticSearchEngine`, and set `ELASTICSEARCH_HOST=host:port`, with commas for additional nodes. You can register `Matchish\ScoutElasticSearch\ElasticSearchServiceProvider` in config/app.php or configure the ElasticSearch client yourself in your own service provider.

Which Elasticsearch versions does the package support?

Elasticsearch 8.0 or newer with ElasticsearchDSL 8.0.0 or newer, Elasticsearch 7.0 with DSL 3.0.0 or newer, and Elasticsearch 6.0 up to but not including 7.0 with a DSL below 3.0.0. The package requires PHP 8.0 or higher and Laravel Framework 8.0.0 or higher, and Laravel below 6.0.0 uses the 3.x branch.

How do I configure index mappings and speed up the import?

Mappings go in the config keys `elasticsearch.indices.mappings.<index>` with a `default` fallback, and settings follow the same pattern under `elasticsearch.indices.settings`. To speed up the import, bind your own `ImportSourceFactory` in the service provider's register method and add the global scopes you want eager loaded.

Official sources

  1. Issues
  2. License: MIT
  3. matchish/laravel-scout-elasticsearch on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/matchish-laravel-scout-elasticsearch.svg)](https://hysenlabs.com/projects/matchish-laravel-scout-elasticsearch)

Was this useful?