mailerlite / laravel-elasticsearch
An easy way to use the official PHP ElasticSearch client in your Laravel applications.
Package info
github.com/mailerlite/laravel-elasticsearch
pkg:composer/mailerlite/laravel-elasticsearch
Fund package maintenance!
Requires
- php: ^8.2
- ext-json: *
- elasticsearch/elasticsearch: ^8.0
- guzzlehttp/guzzle: ^7.0
- guzzlehttp/psr7: ^2.0
- illuminate/contracts: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
- psr/http-message: ^1.1|^2.0
Requires (Dev)
- aws/aws-sdk-php: ^3.80
- mockery/mockery: ^1.4.3
- orchestra/testbench: ^9.0|^10.0|^11.0
- phpunit/phpunit: ^10.5|^11.0|^12.0
Suggests
- aws/aws-sdk-php: Required to connect to an Elasticsearch host on AWS (^3.80)
This package is auto-updated.
Last update: 2026-07-07 03:31:40 UTC
README
An easy way to use the official Elastic Search client in your Laravel applications.
Requirements
- PHP
8.2or higher (Laravel13requires PHP8.3) - Laravel
11,12or13 - An Elasticsearch
8.xcluster
Installation
Install the current version of the mailerlite/laravel-elasticsearch package via composer:
composer require mailerlite/laravel-elasticsearch
This version of the package targets Elasticsearch 8.x. If you are running an older version of Elasticsearch, install the matching major version of this package:
| Elasticsearch | Package version |
|---|---|
| 8.x | ^12 |
| 7.x | ^11 |
For example, to use Elasticsearch 7, install version ^11. Its documentation
lives on the 11.x branch:
composer require mailerlite/laravel-elasticsearch:^11
Note
Upgrading from Elasticsearch 7? Version 12 moves to the Elasticsearch 8.x client, which introduces breaking changes (new namespace, response objects and removed configuration options). See UPGRADING.md for the full migration guide.
Configuration
The package's service provider is registered automatically.
Publish the configuration file:
php artisan vendor:publish --provider="MailerLite\LaravelElasticsearch\ServiceProvider"
Alternative configuration method via .env file
After you publish the configuration file as suggested above, you may configure ElasticSearch
by adding the following to your application's .env file (with appropriate values):
ELASTICSEARCH_HOST=localhost ELASTICSEARCH_PORT=9200 ELASTICSEARCH_SCHEME=http ELASTICSEARCH_USER= ELASTICSEARCH_PASS=
If you are logging in via API keys, you will need to fill in these values:
ELASTICSEARCH_API_ID= ELASTICSEARCH_API_KEY=
Connecting to AWS Elasticsearch Service
If you are connecting to ElasticSearch instances on Amazon AWS, then you'll also
need to composer require aws/aws-sdk-php:^3.80 and add the following to your
.env file:
AWS_ELASTICSEARCH_ENABLED=true AWS_REGION=... AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=...
If you have to use another authentication method having custom credentials (i.e. instanceProfile()),
you have to publish the configuration file and use the aws_credentials:
<?php // config/elasticsearch.php $provider = \Aws\Credentials\CredentialProvider::instanceProfile(); $memoizedProvider = \Aws\Credentials\CredentialProvider::memoize($provider); $credentials = $memoizedProvider()->wait(); ... 'hosts' => [ [ 'host' => env('ELASTICSEARCH_HOST', 'localhost'), // For local development, the default Elasticsearch port is 9200. // If you are connecting to an Elasticsearch instance on AWS, you probably want to set this to null 'port' => env('ELASTICSEARCH_PORT', 9200), 'scheme' => env('ELASTICSEARCH_SCHEME', null), 'user' => env('ELASTICSEARCH_USER', null), 'pass' => env('ELASTICSEARCH_PASS', null), // If you are connecting to an Elasticsearch instance on AWS, you will need these values as well 'aws' => env('AWS_ELASTICSEARCH_ENABLED', false), 'aws_region' => env('AWS_REGION', ''), 'aws_key' => env('AWS_ACCESS_KEY_ID', ''), 'aws_secret' => env('AWS_SECRET_ACCESS_KEY', ''), 'aws_credentials' => $credentials, ], ],
If you have a job that runs in supervisor, you have to use the Closure. This way the credentials will be renewed at runtime.
<?php // config/elasticsearch.php $provider = \Aws\Credentials\CredentialProvider::instanceProfile(); $memoizedProvider = \Aws\Credentials\CredentialProvider::memoize($provider); ... 'hosts' => [ [ ... 'aws_credentials' => $memoizedProvider ], ],
If you are using php artisan config:cache, you cannot have the Closure in your config file, call it like this:
<?php // config/elasticsearch.php ... 'hosts' => [ [ ... 'aws_credentials' => [\Aws\Credentials\CredentialProvider::class, 'defaultProvider'], ], ],
Security and TLS (Elasticsearch 8.x)
Elasticsearch 8 enables TLS and authentication by default. When connecting to a secured cluster you typically need to:
-
Set the scheme to
https:ELASTICSEARCH_SCHEME=https -
Provide credentials, either basic auth (
ELASTICSEARCH_USER/ELASTICSEARCH_PASS) or an API key (ELASTICSEARCH_API_ID/ELASTICSEARCH_API_KEY). -
If the cluster uses a self-signed certificate, point
sslVerificationat the CA bundle (e.g. thehttp_ca.crtgenerated by Elasticsearch) in your published config file:// config/elasticsearch.php 'sslVerification' => '/path/to/http_ca.crt',
For local development only, you can disable certificate verification with
'sslVerification' => false(not recommended in production).
Usage
The Elasticsearch facade is just an entry point into the ES client,
so previously you might have used:
use Elastic\Elasticsearch\ClientBuilder; $data = [ 'body' => [ 'testField' => 'abc' ], 'index' => 'my_index', 'id' => 'my_id', ]; $client = ClientBuilder::create()->build(); $return = $client->index($data);
You can now replace those last two lines with simply:
use Elasticsearch; $return = Elasticsearch::index($data);
That will run the command on the default connection. You can run a command on
any connection (see the defaultConnection setting and connections array in
the configuration file).
$return = Elasticsearch::connection('connectionName')->index($data);
The official Elasticsearch 8.x client no longer returns plain arrays. Every call returns an Elastic\Elasticsearch\Response\Elasticsearch object that implements ArrayAccess, so you can keep accessing keys directly ($return['_id']) or convert it explicitly. By default the client also throws an Elastic\Elasticsearch\Exception\ClientResponseException on 4xx responses and a ServerResponseException on 5xx responses. For HEAD-style endpoints such as indices()->exists() and ping(), resolve the result with ->asBool().
Convert a response explicitly with one of:
$response = Elasticsearch::info(); $response->asArray(); // body as associative array $response->asObject(); // body as stdClass $response->asString(); // raw JSON string $response->asBool(); // true for a 2xx status code
For example, running a search and reading the hits:
$response = Elasticsearch::search([ 'index' => 'my_index', 'body' => [ 'query' => [ 'match' => ['testField' => 'abc'], ], ], ]); $hits = $response['hits']['hits']; // via ArrayAccess // or $hits = $response->asArray()['hits']['hits'];
Instead of the facade, you can also use dependency injection or the application container to get the ES service object:
// using injection: public function handle(\MailerLite\LaravelElasticsearch\Manager $elasticsearch) { $elasticsearch->ping(); } // using the application container: $elasticsearch = app('elasticsearch');
Advanced Usage
Because the package is a wrapper around the official Elastic client, you can do pretty much anything with this package. Not only can you perform standard CRUD operations, but you can monitor the health of your Elastic cluster programmatically, back it up, or make changes to it. Some of these operations are done through "namespaced" commands, which this package happily supports.
To grab statistics for an index:
$stats = Elasticsearch::indices()->stats(['index' => 'my_index']); $stats = Elasticsearch::nodes()->stats(); $stats = Elasticsearch::cluster()->stats();
To create and restore snapshots (read the Elastic docs about creating repository paths and plugins first):
$response = Elasticsearch::snapshots()->create($params); $response = Elasticsearch::snapshots()->restore($params);
To delete whole indices (be careful!):
$response = Elasticsearch::indices()->delete(['index' => 'my_index']);
Please remember that this package is a thin wrapper around a large number of very sophisticated and well-documented Elastic features. Information about those features and the methods and parameters used to call them can be found in the Elastic documentation. Help with using them is available via the Elastic forums and on sites like Stack Overflow.
Console commands
This package also provides some useful console commands.
Check if an index exists:
php artisan laravel-elasticsearch:utils:index-exists <your_elasticsearch_index_name>
Create an index:
php artisan laravel-elasticsearch:utils:index-create <your_elasticsearch_index_name>
Delete an index:
php artisan laravel-elasticsearch:utils:index-delete <your_elasticsearch_index_name>
Create or update index mapping: Note: The index mapping file must contain a valid JSON mapping definition as Elasticsearch expects, for example:
{
"body": {
"_source": {
"enabled": true
},
"properties": {
"id": {
"type": "keyword"
},
"property_1": {
"type": "text"
},
"property_2": {
"type": "text"
}
}
}
}
php artisan laravel-elasticsearch:utils:index-create-or-update-mapping <your_elasticsearch_index_name> <json_mapping_absolute_file_path>
Creates an alias:
php artisan laravel-elasticsearch:utils:alias-create <your_elasticsearch_index_name> <your_elasticsearch_alias_name>
Remove index from an alias:
php artisan laravel-elasticsearch:utils:alias-remove-index <your_elasticsearch_index_name> <your_elasticsearch_alias_name>
Switch index on alias (useful for zero-downtime release of the new index):
php artisan laravel-elasticsearch:utils:alias-switch-index <your_NEW_elasticsearch_index_name> <your_OLD_elasticsearch_index_name> <your_elasticsearch_alias_name>
Bugs, Suggestions, Contributions and Support
Thanks to everyone who has contributed to this project!
Please use Github for reporting bugs, and making comments or suggestions.
See CONTRIBUTING.md for how to contribute changes.
Copyright and License
laravel-elasticsearch was written thanks to Colin Viebrock and is released under the MIT License. It is being maintained and developed by MailerLite
Copyright (c) 2026 MailerLite