vinkla/algolia
Algolia bridge for Laravel that wires the official Algolia PHP client into your app via a service provider, facade, and publishable config. Index and query records, manage indices, and add fast, relevant search to Laravel projects through a clean, familiar API.
vinkla/algolia is a thin Laravel service-provider wrapper around the official algolia/algoliasearch-client-php SDK (v2 era). It does not index Eloquent models for you — that is Laravel Scout's job. Treat it as "the Algolia SDK, pre-wired into the container with a config file and a facade."
Minimal setup:
composer require vinkla/algolia
On Laravel 5.5+ the Vinkla\Algolia\AlgoliaServiceProvider and Vinkla\Algolia\Facades\Algolia facade are auto-discovered. Publish the config and add credentials:
php artisan vendor:publish --provider="Vinkla\Algolia\AlgoliaServiceProvider"
ALGOLIA_APP_ID=XXXXXXXXXX
ALGOLIA_SECRET=your-admin-api-key
First use case — a one-off check from tinker to confirm wiring and credentials before writing any code:
use Algolia\AlgoliaSearch\Client;
$client = app(Client::class);
$client->listIndexes(); // confirms credentials
$client->initIndex('posts')->search('laravel');
Or via the facade:
use Vinkla\Algolia\Facades\Algolia;
Algolia::initIndex('posts')->search('laravel');
Where to look first: config/algolia.php for the bound keys/timeouts, the provider source (it's ~30 lines) to see exactly what is registered, and the Algolia PHP SDK v2 docs — because 95% of what you'll do is just SDK calls, not package API.
Keep the client out of controllers. Inject it into a small service or repository, so the Algolia calls are mockable and the facade isn't sprinkled everywhere:
final class PostSearchIndex
{
public function __construct(private Client $client) {}
public function reindex(iterable $posts): void
{
$index = $this->client->initIndex('posts');
$index->clearObjects();
$index->saveObjects($posts->map(fn ($p) => [
'objectID' => (string) $p->id,
'title' => $p->title,
'body' => $p->body,
])->all());
$index->waitTask($index->getLastTaskId() ?? 0); // or capture the taskID returned
}
}
Index provisioning belongs in an Artisan command, not a migration. Migrations run in CI, on deploy, and locally against production credentials — you don't want an accidental deleteIndex() there. A dedicated algolia:setup command that sets replicas, searchable attributes, synonyms and query rules is the standard pattern.
Zero-downtime reindexing is the most valuable day-to-day use of the raw client. Build into a temp index, then swap:
$client->initIndex('posts_tmp')->saveObjects($records);
$client->copySettings('posts', 'posts_tmp'); // settings first
$client->moveIndex('posts_tmp', 'posts'); // atomic-ish swap, deletes source
moveIndex is destructive on the source, so create the temp index fresh every run. For large datasets, drive it from a queued job rather than a request.
Environment isolation. Never share one index across local/staging/prod. Prefix names in a config value (or a small helper) and make every index name derive from it: posts_{env}. This is the single biggest safeguard against a developer's local clearObjects() wiping the production index.
Coexistence with Scout. If you're already using laravel/scout with the Algolia driver, use Scout for model search/sync and drop to this client only for things Scout doesn't expose: settings, synonyms, query rules, browse, API keys, analytics, index copies. Do not implement two independent indexing paths — keep Scout as the source of truth and treat this package as an admin/ops tool.
Testing. Replace the binding in the container with a mock so unit tests never hit the network:
$this->app->instance(Client::class, $fakeClient);
For integration tests use a dedicated Algolia test app with a throwaway index prefix, and clear it in tearDown().
laravel/scout, which pins a newer algoliasearch-client-php). If you need the SDK today, either use Scout's Algolia engine directly or bind Algolia\AlgoliaSearch\SearchClient yourself — a ~15-line service provider replaces this package.ALGOLIA_SECRET, which is your admin key. Never expose the same client to a browser or a mobile client; use generateSecuredApiKey() or a separate search-only key for anything client-facing.config(['algolia.app_id' => ...])) after resolution won't rebuild the client. Swap the container binding if you need a second app/client.config:cache freezes credentials. Because the config file reads env(), run php artisan config:clear after changing .env in local dev — a stale cached config will silently point at the wrong Algolia app.setSettings(), synonyms, or rule updates, call waitTask($taskId) before relying on query results in tests or in the same request. Otherwise your assertion/UI will see the old behavior.search() returns the first page (default ~20 hits). Use page/hitsPerPage for UI paging and browse() for full exports/reindexing — don't loop search() to fetch tens of thousands of records.AlgoliaException covers 4xx/5xx responses; network failures surface as separate transport exceptions. In commands and jobs, catch both, log the index name and operation, and fail loudly — a silent reindex failure is worse than a crash.algolia (so app('algolia') also works), and Algolia\AlgoliaSearch\Client is bound in the container. Prefer constructor injection of Client::class; reserve the facade for tinker and tiny scripts.Vinkla\Algolia\AlgoliaServiceProvider in bootstrap/app.php and add the facade alias yourself.deleteIndex(), clearObjects(), and moveIndex() don't ask twice and aren't covered by your DB backups. Gate them behind a --force flag in commands and log the index name before executing.How can I help you explore Laravel packages today?