When Elasticsearch Beats Typesense in a Laravel Application

3 min readUpdated on

Typesense with Laravel Scout is an excellent default for fast application search, typo tolerance and ordinary filters. Elasticsearch wins when the search product needs complex aggregations, deep relevance engineering, heterogeneous documents or enormous corpora—and the team will operate mappings, shards, upgrades and cluster incidents.

The cases that justify Elasticsearch

Use it for analytics-style aggregations across millions of documents, custom analyzers per language, synonym and query-time scoring strategies, nested structures, or ranking experiments that need explainable scoring. Do not migrate because Elasticsearch sounds enterprise. Write down a slow query, required facets, target latency and ranking failure that Typesense cannot meet.

Keep the database as source of truth and preserve a service-layer boundary, DTO and reindex job:

php
<?php

declare(strict_types=1);

final readonly class ArticleSearchFilters
{
    /** @param list<string> $tags */
    public function __construct(public string $query, public array $tags, public int $page = 1) {}
}

interface ArticleSearch
{
    public function search(ArticleSearchFilters $filters): SearchResult;
}

The Elasticsearch implementation builds the query and maps hits; controllers do not learn index field names. An observer can enqueue small updates, but a versioned reindex job must rebuild the complete index from the database, verify counts and aliases, then switch reads atomically. External indexes are eventually consistent, so the UI needs an honest freshness expectation.

Compare the product requirement, not the brand

NeedTypesenseElasticsearch
Fast catalogue search and ordinary facetsStrong defaultMore operational weight
Aggregations across huge event corporaLimited fitNative aggregation model
Language analyzers and scoring experimentsLimited tuningDeep query and relevance controls
Cluster, snapshots and shard operationsSimpleRequires ownership

Complete the service boundary

The controller should pass a typed request to one contract and receive a stable result, not learn Elasticsearch fields. The implementation can change mappings without changing HTTP code.

php
<?php

declare(strict_types=1);

namespace App\\Search;

final readonly class ArticleSearchFilters
{
    /** @param list<string> $tags */
    public function __construct(public string $query, public array $tags, public int $page = 1) {}
}

final readonly class SearchResult
{
    /** @param list<array{id: int, title: string}> $items */
    public function __construct(public array $items, public int $total) {}
}

interface ArticleSearch
{
    public function search(ArticleSearchFilters $filters): SearchResult;
}

Reindex through a versioned alias

An observer may enqueue a small document update after commit. A full job must create a new versioned index, read the database in chunks, verify counts and switch the read alias atomically. Never rebuild the live index in place: a failed mapping or partial import otherwise becomes a customer outage.

php
<?php

declare(strict_types=1);

namespace App\\Jobs;

use App\\Models\\Article;
use Illuminate\\Contracts\\Queue\\ShouldQueue;

final class ReindexArticles implements ShouldQueue
{
    public function handle(ArticleIndexer $indexer): void
    {
        $indexer->beginVersion();
        Article::query()->orderBy('id')->chunkById(500, fn ($articles): bool => $indexer->index($articles));
        $indexer->verifyAndSwapAlias();
    }
}

Test mappings against corpus samples, inspect relevance with representative queries, and monitor indexing lag, rejected requests, heap, disk watermarks and snapshot restoration. These are part of the relevance feature, not operations afterthoughts.

Operational costs are part of relevance

Mappings are schemas. Test mapping changes against real corpus samples, monitor rejected requests, heap, disk watermarks, shard size and indexing lag, and rehearse restoring snapshots. More knobs can improve relevance, but each knob creates a future upgrade and incident surface.

When not to use Elasticsearch

Do not choose it for a small catalogue that needs typo-tolerant search and basic facets: Typesense is simpler and usually faster to operate. Do not let a controller call the client directly, and do not treat a successful index write as proof that every replica can serve the result.

Related articles

Existing system support

Need help with a live application?

I help companies improve live systems, clean up delivery workflows, and ship new features without adding avoidable complexity.

Comments (0)
Sign in to leave a comment

You need to be signed in to add a comment.

Login

Need someone to take responsibility for the next step?

Let’s talk about your project and define a scope that actually makes sense for your goals.