FIELD GUIDE 57Infrastructure and security

grafana / loki

Loki keeps log storage cheap by indexing labels, so label design decides everything

Grafana Loki is a horizontally scalable, multi-tenant log aggregation system inspired by Prometheus. It indexes a small set of labels for each log stream instead of the text of every line, and stores compressed logs in object storage. That keeps costs down for as long as the labels stay few and bounded.

WHAT TO KNOW FIRST

  1. Loki indexes labels, not log content; too many label combinations create too many streams, which the docs say leads to a large index and small chunks that hurt performance.
  2. Loki ships with no authentication layer, and multi-tenancy relies on an X-Scope-OrgID header that an authenticating reverse proxy is expected to set.
  3. Retention is off by default, so logs live forever until Compactor retention is enabled, and Simple Scalable mode is deprecated and will not run on Loki 4.0.

01Like Prometheus, but for logs

The grafana/loki README describes a horizontally scalable, highly available, multi-tenant log aggregation system inspired by Prometheus. It does not index the contents of log lines. Instead it indexes a set of labels for each log stream and stores the logs themselves compressed. The labels used for Prometheus metrics can be reused for logs, which lets an operator move from a spike on a dashboard to the log lines behind it. Loki also differs from Prometheus by receiving data through push rather than pull.

The stack in the README has three parts: Grafana Alloy collects logs and sends them, Loki stores them and answers queries, and Grafana queries and displays them. The README notes that Alloy replaced Promtail, which is considered feature complete, so new collection work happens in Alloy. The label documentation also lists Fluentd, Fluent Bit and a Docker logging plugin as clients. Whichever agent is used, it decides most of the labels Loki will see.

02Labels decide cost and speed

The label best practices page is the most important document for a new deployment. Static labels such as region, cluster, application, namespace and environment are good, because they are fixed and bounded. Dynamic labels should be used sparingly, since too many label value combinations create too many streams, and the result is a large index and small chunks in the store, which reduces performance. Label values must always be bounded; trace IDs, order IDs and similar values should never become labels.

For very large tenants sending more than 10 TB a day, the docs suggest staying below 100,000 active streams and a million streams in 24 hours, with proportionally fewer for smaller tenants. They suggest line filters such as |= instead of a level label, and structured metadata for high-cardinality fields that are still useful to attach. The logcli series command with --analyze-labels shows which labels are inflating stream counts, which makes it a good first check after any agent change.

03Deployment modes, and one on its way out

All of Loki's components ship in one binary, and the -target flag decides which ones run. Monolithic mode, with -target=all, runs everything in one process; the docs describe it as suited to getting started and to volumes up to about 20 GB a day, and it can be made highly available with two instances, memberlist, a shared object store and a replication factor of 3. Microservices mode runs each component as a separate process for the largest installations.

Simple Scalable Deployment splits Loki into read, write and backend targets and is the default in the Loki Helm chart, but the docs now carry a caution: SSD mode is being deprecated, will be removed in Loki 4.0, and operators should plan to migrate to microservices or highly available monolithic deployments. The docs quickstart still uses SSD and says so. The README also notes that from March 16, 2026 the Helm chart is maintained in a grafana-community repository, with the in-repository chart kept for Grafana Enterprise Logs users.

04There is no built-in authentication

The authentication page is direct: Grafana Loki does not come with any included authentication layer, and operators must run an authenticating reverse proxy in front of it. In multi-tenant mode, which is the default with auth_enabled set to true, every request needs an X-Scope-OrgID header naming the tenant, and the proxy is expected to set it. A request without the header fails with HTTP 401 and the message no org id. With auth_enabled false, Loki uses a single tenant whose ID is the string fake.

Loki's HTTP and gRPC servers can require client TLS certificates, which the docs describe as native transport-level client authentication, but mutual TLS does not fill in the tenant header, so a proxy, agent or client still has to. Treat the tenant ID as an authorization decision made by the proxy, never by whoever sends logs or queries. Cross-tenant queries are off by default and enabled with multi_tenant_queries_enabled; turn that on only for roles that are meant to see several tenants.

05Retention has to be switched on

Retention is handled by the Compactor, and the docs state plainly that the retention-enabled flag is not set by default, so logs sent to Loki live forever. The Compactor also compacts index files, should run as a single instance, and applies retention on its own schedule; the docs describe both compaction and retention as idempotent, so a restart picks up where it left off. Granular retention per tenant or per stream is supported.

Logs often hold personal data, tokens pasted by mistake and other material with legal retention limits, so an unbounded default is a compliance problem as much as a cost one. Set a retention period for every tenant, shorter periods for noisy or sensitive streams, and check object storage after a period has passed to confirm deletion actually happened. If object store lifecycle rules are used too, make sure they agree with Loki's own retention settings.

06Running it day to day

The documentation covers upgrading, troubleshooting, the LogCLI command-line client and Loki Canary, which watches an installation for missing logs. Building from source needs a current Go toolchain, and the README shows a single-host, no-dependency run built with go build ./cmd/loki and started with a local config file. In the split modes, the write path runs distributors and ingesters, the read path runs query frontends and queriers, and the backend holds the compactor, index gateway, query scheduler and ruler.

Trouble tends to start in a few places: a new label that multiplied streams, a query over a long range without enough label selection, or slow object storage. Alert on stream counts and ingestion rate per tenant, limit query range and parallelism, and keep a canary running so missing logs are noticed by a machine rather than during an outage. The latest release when this guide was checked was v3.7.9, published October 20, 2026, a patch release whose fixes include an ingester WAL ordering bug.

07The license depends on the directory

LICENSING.md sets AGPL-3.0-only as the project's default license. Several directories, including clients/, pkg/push, pkg/logproto and production/, are under Apache-2.0, and vendored code keeps its upstream licenses. The AGPL's conditions are written around distributing the software and offering modified versions to users over a network, so a team that patches Loki and exposes it to customers should review those terms.

The Apache-2.0 client code helps when embedding a push client in another product. Track which parts of the repository a team imports or modifies, and record the license per component in the software inventory instead of assuming the whole tree shares one license. Running the published images unmodified for internal logging is the simplest case to document.

08When Loki fits

Loki fits teams that already run Prometheus and Grafana, collect logs mostly from Kubernetes or containers, and narrow queries by service, namespace and time before searching text. The README notes that on Kubernetes, metadata such as Pod labels is scraped and indexed automatically, which makes it a natural match there. Storing compressed, unindexed log content in object storage is what keeps it cheaper to run, by the README's account.

It is a weaker fit when the main job is fast ad hoc search across many high-cardinality fields such as user or request IDs. Those queries still run as line filters, but they read more data. Try it with a week of real logs, design labels before the agents roll out, and time the searches people actually run during incidents.

A SENSIBLE FIRST HOUR

Start small enough to learn the repo

  1. Follow the docs quickstart: create an evaluate-loki directory, download loki-config.yaml, alloy-local-config.yaml and docker-compose.yaml from the repository's examples/getting-started folder, then run docker compose up -d.
  2. Check that the read component reports ready at http://localhost:3101/ready and the write component at http://localhost:3102/ready, then browse the sample flog logs in the bundled Grafana.
  3. Write one LogQL query that selects streams by labels and a second that adds a line filter with |=, and see how the filter narrows results without adding a label.
  4. Before production, choose monolithic or microservices mode, put an authenticating reverse proxy in front, and enable retention in the Compactor.

SOURCE LEDGER

What this review is built on

We use the project repository and first-party documentation. Access, licenses and project direction can change, so recheck the linked source before making a production decision.

  1. grafana/loki repository and READMErepository
  2. Loki label best practicesdocumentation
  3. Loki deployment modesdocumentation
  4. Loki authenticationdocumentation
  5. Loki multi-tenancydocumentation
  6. Loki retentiondocumentation
  7. Loki quickstartdocumentation
  8. Loki v3.7.9 releaserelease
  9. Loki LICENSING.mdlicense