Choosing a Search Engine Backend for Shopware 6.5+: Elasticsearch, OpenSearch, or MySQL Fulltext
A decision guide for selecting the search engine backend in Shopware 6.5+: compare Elasticsearch, OpenSearch, and MySQL fulltext with constraints, trade-offs, and a concrete OpenSearch validation workflow.
19 Mar 2026, 12:39 UTC

The Decision You Face
Shopware 6.5 requires a search engine for production storefront and administration search. You must pick between Elasticsearch 7.10+, OpenSearch 1.0+, or MySQL 8.0 fulltext. The choice affects relevance quality, operational burden, licensing, and cloud vendor alignment. This guide lays out the constraints, compares the three supported options, and shows how to validate a working OpenSearch setup.
Hard Constraints
- Shopware version: 6.5.x (6.6 may shift requirements; verify before upgrading).
- Production requirement: Elasticsearch 7.10–7.17 or OpenSearch 1.x/2.x. Elasticsearch 8.x is not supported.
- MySQL fulltext: Only for development or catalogs under ~10,000 products. It disables relevance sorting, autocomplete, cross-field search, and partial word matching.
- Client library lock-in: Shopware 6.5 bundles
opensearch-project/opensearch-php ^1.0. Do not mix Elasticsearch and OpenSearch clusters; index templates and client calls are engine-specific. - Reindexing on upgrade: Major Shopware upgrades often require a full reindex. Plan downtime or blue-green indexing.
Supported Options at a Glance
| Engine | Min Version | Max Products | Cloud Support | Analyzer | Real-time | License |
|---|---|---|---|---|---|---|
| Elasticsearch | 7.10 | 1M+ | Elastic Cloud, AWS ES | Full | Yes | SSPL |
| OpenSearch | 1.0 | 1M+ | AWS OpenSearch, Aiven | Full | Yes | Apache 2.0 |
| MySQL Fulltext | 8.0 | ~10k | Any MySQL | Limited | No | GPL |
Trade-offs That Matter
Elasticsearch vs. OpenSearch
Both provide production-grade relevance tuning, faceted navigation, autocomplete, and horizontal scaling. The operational profile is similar: a separate cluster to monitor, version upgrades to coordinate, and memory/CPU to size. The differences are licensing and ecosystem:
- OpenSearch (Apache 2.0) fits AWS-heavy stacks. AWS OpenSearch Service manages patching, fine-grained access control, and VPC integration natively. The plugin ecosystem is smaller but covers security, alerting, and SQL out of the box.
- Elasticsearch (SSPL) offers a broader commercial plugin marketplace and official support contracts via Elastic. Elastic Cloud provides managed clusters across AWS, GCP, and Azure. If your organization already standardizes on Elastic tooling (Kibana, Beats, Fleet), staying on Elasticsearch reduces learning curve.
OpenSearch 2.x introduced breaking changes in its security plugin. Shopware 6.5 pins opensearch-php ^1.0, which targets OpenSearch 1.x APIs. If you run OpenSearch 2.x, verify compatibility or stay on 1.x until Shopware updates the client.
MySQL Fulltext: The "No External Dependency" Path
MySQL 8.0 fulltext eliminates a separate search cluster, reducing cost and operational surface. It works for small catalogs (<10k products) and low traffic. However, you lose:
- Stemming and synonym expansion (searching "shoe" won't match "shoes").
- Partial word matching (no prefix/wildcard queries performant at scale).
- Relevance-based sorting — results return in arbitrary order.
- Autocomplete and cross-field search (e.g., searching SKU + name + description simultaneously).
- High write throughput during reindexing; large catalog updates block the database.
If you start with MySQL fulltext and grow past 10k products, migration to Elasticsearch/OpenSearch requires a full reindex and configuration change — plan for it early.
Concrete Implementation: OpenSearch on Docker Compose
The following steps assume a Linux/macOS host with Docker and Docker Compose installed. Run commands from your Shopware project root. You need sudo or Docker group membership to manage containers.
1. Add OpenSearch to docker-compose.override.yml
version: '3.8'
services:
opensearch:
image: opensearchproject/opensearch:1.3.12
environment:
- discovery.type=single-node
- OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g
- plugins.security.disabled=true
ports:
- "9200:9200"
- "9600:9600"
volumes:
- opensearch_data:/var/lib/opensearch
networks:
- default
volumes:
opensearch_data:
Risk: plugins.security.disabled=true is for local development only. Production must enable security and create a dedicated Shopware user with index/* permissions on the index prefix.
2. Configure Shopware .env
SHOPWARE_ES_HOSTS=opensearch:9200
SHOPWARE_ES_INDEX_PREFIX=sw6_
SHOPWARE_ES_ENABLED=1
SHOPWARE_ES_USERNAME=admin
SHOPWARE_ES_PASSWORD=secret
Replace admin/secret with your actual credentials if security is enabled. The SHOPWARE_ES_INDEX_PREFIX isolates Shopware indices if the cluster is shared.
3. Start the Stack and Populate Indices
docker compose up -d opensearch
# Wait for cluster health green
curl -s http://localhost:9200/_cluster/health | jq .status
# Populate indices (run inside PHP container or host with PHP CLI)
bin/console opensearch:index:populate --batch-size=500 --no-interaction
Expected check: The populate command exits 0 and logs "Indexing finished" for each entity type (product, category, rule, etc.). For catalogs >100k products, increase PHP memory_limit (e.g., -d memory_limit=1G) and run multiple messenger:consume opensearch_indexer workers in parallel.
Validation: Prove It Works
- Index status:
bin/console opensearch:index:statusshould list indicessw6_product_*,sw6_category_*, etc., with document counts matching your catalog. - Storefront search test: Search for a known product SKU in the storefront. Verify:
- Response time < 200 ms (p95) — check browser dev tools Network tab.
- Result includes the expected product with highlighted match in name/description.
- Facet counts (category, price range, properties) match actual product counts.
- Queue health: Run
bin/console messenger:consume opensearch_indexer -vvand watch for lag. In production, monitor the queue via Shopware Profiler or OpenSearch_cat/indices?vAPI —docs.countshould stay current after product updates. - Load test (optional but recommended): Use
k6orsiegewith 50 concurrent search requests for 60 seconds. Target: p95 < 300 ms, zero 5xx errors. Examplek6script:import http from 'k6/http'; export const options = { vus: 50, duration: '60s' }; export default function () { http.get('https://your-shop.example.com/search?q=test'); }
Limitations and Gotchas
- Version drift: Shopware 6.5 does not support Elasticsearch 8.x or OpenSearch 2.x security plugin changes. Pin your managed service version (e.g., AWS OpenSearch 1.3) until Shopware certifies newer releases.
- Index template mismatch: If you manually create indices or change mappings, Shopware's populate command may fail. Let Shopware manage templates; only adjust analyzer settings via
config/packages/shopware.ymlif you understand the impact. - Reindexing cost: Full reindex on 500k+ products can take hours. Use
--batch-sizeand parallel consumers. Consider blue-green: populate a new index prefix, then flipSHOPWARE_ES_INDEX_PREFIXatomically. - Logging: Indexer errors appear in
var/log/opensearch_indexer.log. Check after initial populate and after every product import/update.
Quick Verification Checklist
bin/console system:checkreports search engine connectivity and version OK.- OpenSearch Dashboards (port 5601) shows
sw6_product_*indices with custom analyzers (e.g.,sw_analyzer) applied. - Search for a partial word (e.g., "book" matches "notebook") — confirms analyzer works.
- Facet aggregation returns correct counts after adding/removing products.
Decision Summary
For production Shopware 6.5 stores:
- Default to OpenSearch 1.x if you run on AWS or want Apache 2.0 licensing.
- Choose Elasticsearch 7.17 if you need commercial support, broader plugins, or multi-cloud managed service.
- Use MySQL fulltext only for local dev, demos, or catalogs under 10k products with no relevance requirements.
Validate with the steps above before committing. A working OpenSearch cluster with populated indices and sub-200 ms storefront search is your definition of done.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.