Loki and Elasticsearch solve the same problem β aggregate and search logs β but with fundamentally different architectures. Elasticsearch indexes the full content of every log line. Loki only indexes labels (metadata) and stores log content as compressed chunks. This difference drives everything: cost, performance, query capability, and operational complexity.
Architecture
Elasticsearch (ELK/EFK)
Elasticsearch builds a full-text inverted index for every log line:
Log line β Tokenized β Inverted index β Stored in shards- Every word in every log line is indexed and searchable
- Shards distributed across nodes for horizontal scaling
- JVM-based β requires significant heap memory
- Typically paired with Kibana (visualization) and Filebeat/Fluentd (collection)
Grafana Loki
Loki indexes only labels, not log content:
Log line β Labels indexed β Content stored as compressed chunks in object storage- Labels (namespace, pod, container, app) are indexed in a small index
- Log content stored as compressed chunks in S3/GCS/MinIO
- Queries filter by labels first, then grep through matching chunks
- Paired with Grafana (visualization) and Promtail/Alloy (collection)
Feature comparison
| Feature | Loki | Elasticsearch |
|---|---|---|
| Indexing | Labels only | Full-text inverted index |
| Query language | LogQL (Prometheus-like) | KQL / Lucene / ES |
| Storage backend | Object storage (S3, GCS, MinIO) | Local SSD (primary) |
| Storage cost | ~$0.02/GB (S3) | ~$0.10/GB (SSD) |
| Memory per node | 1-4 GB | 16-64 GB (JVM heap) |
| Ingest rate | High (append-only) | High (index overhead) |
| Full-text search | Grep-based (slower) | Inverted index (fast) |
| Structured queries | Label filtering + LogQL | Arbitrary field queries |
| Visualization | Grafana | Kibana |
| Alerts | Grafana Alerting / Loki Ruler | Elasticsearch Watcher / Kibana |
| Multi-tenancy | Built-in (tenant header) | Index-per-tenant |
| CNCF/License | AGPL v3 (Grafana Labs) | SSPL (Elastic) / Apache 2.0 (OpenSearch) |
Cost comparison
This is Lokiβs biggest advantage:
Storage (100 GB/day of logs, 30-day retention)
| Loki (S3) | Elasticsearch (SSD) | |
|---|---|---|
| Raw log volume | 3 TB | 3 TB |
| Actual storage | ~600 GB (compressed) | ~6 TB (index + replicas) |
| Storage cost/mo | ~$14 | ~$600 |
| Compute (3 nodes) | ~$300/mo | ~$900/mo |
| Total monthly | ~$314 | ~$1,500 |
Loki is 3-5x cheaper because:
- No full-text index (saves 2-3x storage)
- Object storage ($0.02/GB) vs SSD ($0.10/GB)
- Lower memory requirements (no JVM heap)
- Compressed chunks (5-10x compression ratio)
At scale (1 TB/day)
| Loki | Elasticsearch | |
|---|---|---|
| Monthly storage | ~$140 | ~$6,000 |
| Compute | ~$2,000 | ~$8,000 |
| Total | ~$2,140 | ~$14,000 |
The cost gap widens with volume.
Query language
LogQL (Loki)
LogQL is designed like PromQL β label selectors first, then line filters:
# All error logs from the api service
{namespace="production", app="api"} |= "error"
# Parse JSON logs and filter by status code
{app="api"} | json | status >= 500
# Count errors per minute
count_over_time({app="api"} |= "error" [1m])
# Top 10 endpoints by error count
topk(10,
sum by (path) (
count_over_time({app="api"} | json | status >= 500 [1h])
)
)KQL (Elasticsearch/Kibana)
# Full-text search
message: "connection refused" AND kubernetes.namespace: "production"
# Structured query
status: >= 500 AND service: "api"
# Aggregation (via ES|QL)
FROM logs
| WHERE status >= 500
| STATS count = COUNT(*) BY service
| SORT count DESC
| LIMIT 10Elasticsearch is better for ad-hoc full-text search β βfind all logs containing this error message across all services.β The inverted index makes this fast regardless of volume.
Loki is better for label-filtered queries β βshow me errors from this specific pod in the last hour.β If you know which service you are looking at, Loki is efficient.
Operational complexity
| Aspect | Loki | Elasticsearch |
|---|---|---|
| Installation | Helm chart, 3 components | Helm chart, 3+ nodes |
| Cluster management | Stateless (object storage) | Stateful (shard management) |
| Upgrades | Rolling update (stateless) | Rolling restart (careful shard allocation) |
| Scaling | Add read/write replicas | Add data/ingest nodes, rebalance shards |
| Disk management | Object storage (unlimited) | Monitor disk, add nodes before full |
| JVM tuning | N/A | Heap size, GC tuning, circuit breakers |
| Index management | Automatic retention | ILM policies, rollover, force merge |
| Backup | Object storage (inherent durability) | Snapshot to S3 |
Loki is simpler to operate because it is stateless β log data lives in object storage. Elasticsearch requires careful shard management, JVM tuning, and disk monitoring.
Kubernetes deployment
Loki (simple scalable mode)
helm install loki grafana/loki \
--set loki.storage.type=s3 \
--set loki.storage.s3.endpoint=s3.amazonaws.com \
--set loki.storage.s3.bucketnames=my-loki-logs \
--set loki.storage.s3.region=eu-west-1 \
--set deploymentMode=SimpleScalable \
--set read.replicas=3 \
--set write.replicas=3
# Install Promtail for log collection
helm install promtail grafana/promtail \
--set config.clients[0].url=http://loki:3100/loki/api/v1/pushElasticsearch (ECK operator)
# Install ECK operator
kubectl create -f https://download.elastic.co/downloads/eck/2.14.0/crds.yaml
kubectl apply -f https://download.elastic.co/downloads/eck/2.14.0/operator.yaml
# Deploy Elasticsearch cluster
cat <<EOF | kubectl apply -f -
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: logs
spec:
version: 8.15.0
nodeSets:
- name: default
count: 3
config:
node.store.allow_mmap: false
volumeClaimTemplates:
- metadata:
name: elasticsearch-data
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 500Gi
storageClassName: gp3
EOFDecision guide
Choose Loki when:
- Cost is a priority β 3-5x cheaper at scale
- You already use Grafana for metrics dashboards
- Your queries are label-based (specific service, namespace, pod)
- You want simple operations β stateless components, object storage
- You are a small/medium team without dedicated Elasticsearch expertise
- Log retention is long (30+ days) β object storage costs scale linearly
Choose Elasticsearch when:
- You need full-text search across all logs β βfind this error anywhereβ
- You have compliance requirements for log analytics (SIEM, audit)
- You need complex aggregations on structured log fields
- You already run Kibana and your team knows KQL
- You have dedicated platform engineers who can manage Elasticsearch
- You need sub-second search on arbitrary text patterns
Consider OpenSearch
OpenSearch is the Apache 2.0 fork of Elasticsearch. Same capabilities, no SSPL license concerns. Choose OpenSearch if you need Elasticsearch features but want a truly open-source license.