Grafana Loki is a log aggregation engine replacing Splunk and CloudWatch Logs with cost-effective label indexing and native S3 object storage.
Splunk meters logging bills by ingested gigabytes and inflates storage footprints through universal inverted indexing. Grafana Loki discards full-text indexing at write time in favor of lightweight stream labels, writing compressed chunks directly to commodity object storage. This architecture lets engineering teams retain months of application and cluster telemetry at object-storage rates rather than capping retention to manage software invoices.
Splunk builds an inverted index across every token in every log line, requiring substantial memory, fast NVMe drives, and ongoing index maintenance. Loki adopts the opposite design: it indexes only stream metadata—such as Kubernetes namespace, pod, container, or environment—and stores compressed log data in object stores like AWS S3, Google Cloud Storage, or MinIO. This design eliminates the ingest tax and storage multiplier associated with Splunk licenses, making high-volume debug logs practical to keep.
The trade-off shifts during queries. Splunk charges for ingestion upfront but delivers fast ad-hoc text search across historical logs via pre-computed indexes. Loki incurs minimal ingestion cost, instead shifting compute to query time by executing parallel scans across chunks with LogQL. While Loki lacks Splunk's enterprise security information and event management (SIEM) rules and cross-dataset joins, it integrates directly with Prometheus and Grafana so engineers can pivot from metric spikes to logs without per-gigabyte SaaS fees.
Is Grafana Loki free for commercial use? Yes, Grafana Loki is open-source software that teams can host internally without licensing fees. Operational costs come down to the compute and object storage required to run it.
Grafana Loki vs Splunk — which should an engineering team choose? Choose Grafana Loki for cost-effective log aggregation and Kubernetes troubleshooting unified with Prometheus and Grafana. Choose Splunk if you require enterprise SIEM security features, compliance automation, and instant full-text search across unindexed data.
Can Grafana Loki run entirely on cloud object storage like Amazon S3? Yes, Loki stores both TSDB index files and compressed log chunks directly in object storage like Amazon S3 or MinIO without an external database.
Grafana Loki is an ideal choice when log volume makes commercial SaaS tools unaffordable and your stack already standardizes on Prometheus and Grafana; it is not suited for security teams requiring out-of-the-box SIEM threat detection. Active maintenance with commits through late 2026 and an AGPL-3.0 license make it a dependable foundation for internal developer platforms, provided you do not plan to distribute proprietary managed modifications.
Commands from the official package registries. Each package is matched to Grafana Loki through the registry's own link to its source code or website.
brew install lokibrew install lokisudo pacman -S lokiWe started this exact setup from scratch in a clean Linux machine on Nov 1, 2026 and checked it through Grafana Loki's own API: every check passed. Recipes are re-checked regularly and removed if they stop working.
mkdir -p loki && cd loki
curl -fsSL https://open-source.store/tools/loki/compose.yml -o compose.ymltouch .envdocker compose up -dservices:
loki:
image: grafana/loki:3.7.9
ports:
- "127.0.0.1:3100:3100"
volumes:
- loki-data:/loki
restart: always
healthcheck:
test: ["CMD", "/usr/bin/loki", "-health"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
volumes:
loki-data: {}
Go, gRPC and Protobuf done right, LLM agents in production, and the hard parts of shipping a first product.
Show that Grafana Loki is listed as an open-source alternative. Paste into your README:
Ubuntu 24.04 · Apple container, Docker 29.1.3, Compose 2.40.3+ds1-0ubuntu1~24.04.1. Images pulled in 7 s: grafana/loki:3.7.9.
Based on the upstream setup. Official Docker setup with named volume for local data. Image pinned to 3.7.9, bound to 127.0.0.1 because Loki has no native authentication, and built-in healthcheck enabled.
loki-1 | 2026-11-01T03:24:27.783154129Z level=info ts=2026-11-01T03:24:27.676620921Z caller=main.go:146 msg="Starting Loki" version="(version=3.7.9, branch=release-3.7.x, revision=d3b4a2f7)" loki-1 | 2026-11-01T03:24:27.783178504Z level=info ts=2026-11-01T03:24:27.676646629Z caller=main.go:147 msg="Loading configuration file" filename=/etc/loki/local-config.yaml loki-1 | 2026-11-01T03:24:27.783180129Z level=info ts=2026-11-01T03:24:27.677479962Z caller=server.go:397 msg="server listening on addresses" http=[::]:3100 grpc=[::]:9095 loki-1 | 2026-11-01T03:24:27.783180962Z level=info ts=2026-11-01T03:24:27.679116712Z caller=table_manager.go:136 index-store=tsdb-2020-10-24 msg="uploading tables" loki-1 | 2026-11-01T03:24:27.783181671Z level=info ts=2026-11-01T03:24:27.679183546Z caller=table_manager.go:300 index-store=tsdb-2020-10-24 msg="query readiness setup completed" duration=1.042µs distinct_users_len=0 distinct_users= loki-1 | 2026-11-01T03:24:27.783182962Z level=info ts=2026-11-01T03:24:27.679201754Z caller=shipper.go:165 index-store=tsdb-2020-10-24 msg="starting index shipper in RW mode" loki-1 | 2026-11-01T03:24:27.783183587Z level=info ts=2026-11-01T03:24:27.679702837Z caller=head_manager.go:324 index-store=tsdb-2020-10-24 component=tsdb-head-manager msg="loaded wals by period" groups=0 loki-1 | 2026-11-01T03:24:27.783184296Z level=info ts=2026-11-01T03:24:27.679738671Z caller=manager.go:86 index-store=tsdb-2020-10-24 component=tsdb-manager msg="loaded leftover local indices" err=null successful=true buckets=0 indices=0 failures=0 loki-1 | 2026-11-01T03:24:27.783185004Z level=info ts=2026-11-01T03:24:27.679747421Z caller=head_manager.go:324 index-store=tsdb-2020-10-24 component=tsdb-head-manager msg="loaded wals by period" groups=0 loki-1 | 2026-11-01T03:24:27.783185671Z level=info ts=2026-11-01T03:24:27.682045379Z caller=worker.go:134 component=querier msg="Starting querier worker using query-scheduler and scheduler ring for addresses" loki-1 | 2026-11-01T03:24:27.783186379Z level=info ts=2026-11-01T03:24:27.682210462Z caller=mapper.go:47 msg="cleaning up mapped rules directory" path=/loki/rules-temp loki-1 | 2026-11-01T03:24:27.783187004Z level=info ts=2026-11-01T03:24:27.689748087Z caller=module_service.go:82 msg=starting module=cache-generation-loader loki-1 | 2026-11-01T03:24:27.783187629Z level=info ts=2026-11-01T03:24:27.689756921Z caller=module_service.go:82 msg=starting module=server loki-1 | 2026-11-01T03:24:27.783192671Z level=info ts=2026-11-01T03:24:27.690290129Z caller=module_service.go:82 msg=starting module=memberlist-kv loki-1 | 2026-11-01T03:24:27.783194337Z level=info ts=2026-11-01T03:24:27.690301046Z caller=module_service.go:82 msg=starting module=query-frontend-tripperware loki-1 | 2026-11-01T03:24:27.783194962Z level=info ts=2026-11-01T03:24:27.690311712Z caller=module_service.go:82 msg=starting module=query-scheduler-ring loki-1 | 2026-11-01T03:24:27.783195504Z level=info ts=2026-11-01T03:24:27.690381171Z caller=ring.go:390 msg="ring doesn't exist in KV store yet" loki-1 | 2026-11-01T03:24:27.783196129Z level=info ts=2026-11-01T03:24:27.690451587Z caller=module_service.go:82 msg=starting module=store loki-1 | 2026-11-01T03:24:27.783196671Z level=info ts=2026-11-01T03:24:27.690501087Z caller=module_service.go:82 msg=starting module=ring loki-1 | 2026-11-01T03:24:27.783197254Z level=info ts=2026-11-01T03:24:27.690535379Z caller=ring.go:390 msg="ring doesn't exist in KV store yet" loki-1 | 2026-11-01T03:24:27.783199004Z level=info ts=2026-11-01T03:24:27.690548212Z caller=basic_lifecycler.go:324 msg="instance not found in the ring" instance=c54c418c41e4 ring=scheduler loki-1 | 2026-11-01T03:24:27.783199837Z level=info ts=2026-11-01T03:24:27.690555212Z caller=basic_lifecycler_delegates.go:63 msg="not loading tokens from file, tokens file path is empty" loki-1 | 2026-11-01T03:24:27.783200504Z level=info ts=2026-11-01T03:24:27.690669421Z caller=module_service.go:82 msg=starting module=analytics loki-1 | 2026-11-01T03:24:27.783201087Z level=info ts=2026-11-01T03:24:27.690890212Z caller=ringmanager.go:186 msg="waiting until scheduler is JOINING in the ring" loki-1 | 2026-11-01T03:24:27.783201671Z level=info ts=2026-11-01T03:24:27.690897879Z caller=ringmanager.go:190 msg="scheduler is JOINING in the ring" loki-1 | 2026-11-01T03:24:27.783202254Z level=info ts=2026-11-01T03:24:27.690917046Z caller=ringmanager.go:199 msg="waiting until scheduler is ACTIVE in the ring" loki-1 | 2026-11-01T03:24:27.783202879Z level=info ts=2026-11-01T03:24:27.691025629Z caller=module_service.go:82 msg=starting module=distributor loki-1 | 2026-11-01T03:24:27.783203462Z level=error ts=2026-11-01T03:24:27.691085129Z caller=ratestore.go:110 msg="error getting ingester clients" err="empty ring" loki-1 | 2026-11-01T03:24:27.783204087Z level=info ts=2026-11-01T03:24:27.691175754Z caller=module_service.go:82 msg=starting module=ingester-querier loki-1 | 2026-11-01T03:24:27.783204671Z level=info ts=2026-11-01T03:24:27.691223671Z caller=module_service.go:82 msg=starting module=rule-evaluator loki-1 | 2026-11-01T03:24:27.783205254Z level=info ts=2026-11-01T03:24:27.691236129Z caller=module_service.go:82 msg=starting module=ingester loki-1 | 2026-11-01T03:24:27.783205921Z level=info ts=2026-11-01T03:24:27.691264837Z caller=ingester.go:571 component=ingester msg="recovering from checkpoint" loki-1 | 2026-11-01T03:24:27.783206504Z level=info ts=2026-11-01T03:24:27.691278962Z caller=checkpoint.go:549 msg="tmp checkpoint cleanup starting" loki-1 | 2026-11-01T03:24:27.783207087Z level=info ts=2026-11-01T03:24:27.691309379Z caller=checkpoint.go:554 msg="tmp checkpoint cleanup done" duration=13.333µs success=true loki-1 | 2026-11-01T03:24:27.783207754Z level=info ts=2026-11-01T03:24:27.691318837Z caller=recovery.go:45 component=ingester msg="no checkpoint found, treating as no-op" loki-1 | 2026-11-01T03:24:27.783208379Z level=info ts=2026-11-01T03:24:27.691354421Z caller=module_service.go:82 msg=starting module=compactor loki-1 | 2026-11-01T03:24:27.783208962Z level=info ts=2026-11-01T03:24:27.691422004Z caller=ring.go:390 msg="ring doesn't exist in KV store yet" loki-1 | 2026-11-01T03:24:27.783209546Z level=info ts=2026-11-01T03:24:27.691592087Z caller=basic_lifecycler.go:324 component=distributor msg="instance not found in the ring" instance=c54c418c41e4 ring=distributor loki-1 | 2026-11-01T03:24:27.783210212Z level=info ts=2026-11-01T03:24:27.691672837Z caller=basic_lifecycler.go:324 msg="instance not found in the ring" instance=c54c418c41e4 ring=compactor loki-1 | 2026-11-01T03:24:27.783210837Z level=info ts=2026-11-01T03:24:27.691677546Z caller=basic_lifecycler_delegates.go:63 msg="not loading tokens from file, tokens file path is empty" loki-1 | 2026-11-01T03:24:27.783211462Z level=info ts=2026-11-01T03:24:27.691768629Z caller=module_service.go:82 msg=starting module=ruler loki-1 | 2026-11-01T03:24:27.783212004Z level=info ts=2026-11-01T03:24:27.692008962Z caller=ruler.go:536 msg="ruler up and running" loki-1 | 2026-11-01T03:24:27.783212962Z level=info ts=2026-11-01T03:24:27.692035712Z caller=ingester.go:587 component=ingester msg="recovered WAL checkpoint recovery finished" elapsed=771.834µs errors=false loki-1 | 2026-11-01T03:24:27.783213629Z level=info ts=2026-11-01T03:24:27.692040962Z caller=ingester.go:593 component=ingester msg="recovering from WAL" loki-1 | 2026-11-01T03:24:27.783214212Z level=info ts=2026-11-01T03:24:27.692063504Z caller=compactor.go:420 msg="waiting until compactor is JOINING in the ring" loki-1 | 2026-11-01T03:24:27.783214837Z level=info ts=2026-11-01T03:24:27.692066171Z caller=compactor.go:424 msg="compactor is JOINING in the ring" loki-1 | 2026-11-01T03:24:27.783215421Z level=info ts=2026-11-01T03:24:27.692083504Z caller=compactor.go:434 msg="waiting until compactor is ACTIVE in the ring" loki-1 | 2026-11-01T03:24:27.783216004Z level=info ts=2026-11-01T03:24:27.692550212Z caller=ingester.go:609 component=ingester msg="WAL segment recovery finished" elapsed=1.286125ms errors=false loki-1 | 2026-11-01T03:24:27.783216754Z level=info ts=2026-11-01T03:24:27.692555504Z caller=ingester.go:557 component=ingester msg="closing recoverer" loki-1 | 2026-11-01T03:24:27.783217337Z level=info ts=2026-11-01T03:24:27.692580171Z caller=ingester.go:565 component=ingester msg="WAL recovery finished" time=1.313959ms loki-1 | 2026-11-01T03:24:27.783217962Z level=info ts=2026-11-01T03:24:27.692612296Z caller=lifecycler.go:694 component=ingester msg="not loading tokens from file, tokens file path is empty" loki-1 | 2026-11-01T03:24:27.783218587Z level=info ts=2026-11-01T03:24:27.692625754Z caller=lifecycler.go:721 component=ingester msg="instance not found in ring, adding with no tokens" ring=ingester loki-1 | 2026-11-01T03:24:27.783219254Z level=info ts=2026-11-01T03:24:27.692648796Z caller=lifecycler.go:562 component=ingester msg="auto-joining cluster after timeout" ring=ingester loki-1 | 2026-11-01T03:24:27.783219879Z level=info ts=2026-11-01T03:24:27.692924629Z caller=wal.go:173 msg=started component=wal loki-1 | 2026-11-01T03:24:27.783220462Z level=info ts=2026-11-01T03:24:27.693045921Z caller=ingester.go:778 component=ingester msg="sleeping for initial delay before starting periodic flushing" delay=2.261030119s loki-1 | 2026-11-01T03:24:27.848269504Z level=info ts=2026-11-01T03:24:27.844806587Z caller=compactor.go:438 msg="compactor is ACTIVE in the ring" loki-1 | 2026-11-01T03:24:27.848286629Z level=info ts=2026-11-01T03:24:27.848048629Z caller=ringmanager.go:203 msg="scheduler is ACTIVE in the ring" loki-1 | 2026-11-01T03:24:27.848287546Z level=info ts=2026-11-01T03:24:27.848076171Z caller=module_service.go:82 msg=starting module=query-scheduler loki-1 | 2026-11-01T03:24:27.848288212Z level=info ts=2026-11-01T03:24:27.848143962Z caller=module_service.go:82 msg=starting module=querier loki-1 | 2026-11-01T03:24:27.848288837Z level=info ts=2026-11-01T03:24:27.848145837Z caller=module_service.go:82 msg=starting module=query-frontend loki-1 | 2026-11-01T03:24:27.848289379Z level=info ts=2026-11-01T03:24:27.848176921Z caller=loki.go:615 msg="Loki started" startup_time=210.970208ms loki-1 | 2026-11-01T03:24:30.883160755Z level=info ts=2026-11-01T03:24:30.848946047Z caller=scheduler.go:658 msg="this scheduler is in the ReplicationSet, will now accept requests." loki-1 | 2026-11-01T03:24:30.883216589Z level=info ts=2026-11-01T03:24:30.848960964Z caller=worker.go:235 component=querier msg="adding connection" addr=127.0.0.1:9095 loki-1 | 2026-11-01T03:24:32.876448131Z level=info ts=2026-11-01T03:24:32.845376798Z caller=compactor.go:497 msg="this instance has been chosen to run the compactor, starting compactor" loki-1 | 2026-11-01T03:24:32.876491256Z level=info ts=2026-11-01T03:24:32.845465548Z caller=tables_manager.go:70 msg="waiting 10m0s for ring to stay stable and previous compactions to finish before starting compactor" loki-1 | 2026-11-01T03:24:37.873916967Z level=info ts=2026-11-01T03:24:37.848670717Z caller=frontend_scheduler_worker.go:106 msg="adding connection to scheduler" addr=127.0.0.1:9095 loki-1 | 2026-11-01T03:24:45.774311304Z level=info ts=2026-11-01T03:24:45.757020846Z caller=roundtrip.go:412 org_id=fake msg="executing query" type=labels label= length=1h0m0s query= loki-1 | 2026-11-01T03:24:45.774441221Z level=info ts=2026-11-01T03:24:45.759333554Z caller=table_manager.go:195 index-store=tsdb-2020-10-24 msg="get or create table" found=false table=index_20758 wait_for_lock=917ns loki-1 | 2026-11-01T03:24:45.774460596Z level=info ts=2026-11-01T03:24:45.759360596Z caller=table_manager.go:205 index-store=tsdb-2020-10-24 msg="downloading all files for table" table=index_20758 loki-1 | 2026-11-01T03:24:45.774461929Z ts=2026-11-01T03:24:45.760202596Z caller=spanlogger.go:152 table-name=index_20758 user-id=fake user=fake level=info msg="init index set" duration=239.417µs success=true loki-1 | 2026-11-01T03:24:45.774463221Z ts=2026-11-01T03:24:45.760219762Z caller=spanlogger.go:152 table-name=index_20758 user-id=fake user=fake level=info msg="downloaded index set at query time" duration=239.417µs loki-1 | 2026-11-01T03:24:45.774463929Z ts=2026-11-01T03:24:45.760285471Z caller=spanlogger.go:152 table-name=index_20758 user=fake level=info msg="init index set" duration=42.625µs success=true loki-1 | 2026-11-01T03:24:45.774464638Z ts=2026-11-01T03:24:45.760290804Z caller=spanlogger.go:152 table-name=index_20758 user=fake level=info msg="downloaded index set at query time" duration=42.625µs loki-1 | 2026-11-01T03:24:45.774466596Z level=info ts=2026-11-01T03:24:45.760500971Z caller=metrics.go:340 org_id=fake latency=fast query_type=labels splits=0 start=2026-11-01T02:24:45.757011846Z end=2026-11-01T03:24:45.757011846Z start_delta=1h0m0.003485708s end_delta=3.486125ms length=1h0m0s duration=2.410959ms status=200 label= query= query_hash=2166136261 total_entries=0 cache_label_results_req=0 cache_label_results_hit=0 cache_label_results_stored=0 cache_label_results_download_time=0s cache_label_results_query_length_served=0s loki-1 | 2026-11-01T03:24:45.774472721Z level=info ts=2026-11-01T03:24:45.761722512Z caller=metrics.go:340 component=frontend org_id=fake latency=fast query_type=labels splits=0 start=2026-11-01T02:24:45.757011846Z end=2026-11-01T03:24:45.757011846Z start_delta=1h0m0.004707792s end_delta=4.707834ms length=1h0m0s duration=4.571042ms status=200 label= query= query_hash=2166136261 total_entries=0 cache_label_results_req=0 cache_label_results_hit=0 cache_label_results_stored=0 cache_label_results_download_time=0s cache_label_results_query_length_served=0s