---
icon: material/rocket-launch-outline
---

Deploy the [Retriever](../) in the shape that fits your workload. Kubernetes and Lambda are the two modes, and the choice is reversible.

Both use the same engine image and write the same object storage layout, so an index built by one is readable by the other and moving later costs no re-indexing. On Kubernetes that layout can sit in S3 or in [Azure Blob Storage](azure.md).

They differ in how the work is split. Kubernetes runs three configurable roles (`index`, `query`, `stream`), where the query role handles sub-queries internally. Lambda fans out into four separate functions (`indexer`, `query`, `subquery`, `stream`).

## At a glance

| | :material-lambda: **Lambda** | :material-kubernetes: **Kubernetes** |
|---|---|---|
| **Best for** | Bursty query traffic, low ops, pay-per-invocation | Steady high-volume ingest, in-cluster neighbors |
| **Always-on cost** | ~$0 (optional warm pool via Provisioned Concurrency) | Always-on pods |
| **Cold query p50** | ~7 s (sub-10 s with Provisioned Concurrency) | ~2 s |
| **Warm query p50** | ~1.2 s | ~1 s |
| **Index scaling** | SQS batch × per-function concurrency | HPA on the indexer cluster |
| **Event output** | Pipeline emits directly to the analyzer | Fluent Bit sidecar on stream pods |
| **Max query time** | 15 min (Lambda hard limit) | Unbounded |
| **Clouds** | AWS | AWS EKS, Azure AKS (GKE, self-hosted on roadmap) |
| **Object storage** | S3, or any S3-compatible store | S3, any S3-compatible store, or [Azure Blob](azure.md) |
| **→** | **[Deploy on Lambda](lambda.md)** | **[Deploy on Kubernetes](k8s.md)** or **[on Azure](azure.md)** |

## Cost of keeping the offload queryable { #cost-at-1-tbday }

The Retriever holds the cohort the Receiver offloaded to your S3, the slice that exceeded your analyzer budget, and indexes it in place to fetch back on demand. It is the overflow tier behind your analyzer, not a wholesale replacement for it. The table prices 1 TB/day of *offloaded* logs (not your total ingest), 30-day S3 lifecycle, 1000 fetch queries/day. Vendor rows are published list prices before enterprise discount.

| Stack | Monthly | Query latency |
|---|---|---|
| :material-kubernetes: **[Retriever on Kubernetes](k8s.md)** | **~$1,500** | ~1 s warm · ~2 s cold |
| :material-lambda: **[Retriever on Lambda](lambda.md)** | **~$2,945** | ~1.2 s warm · ~7 s cold |
| DIY Parquet + Athena | $2K–$3K + engineering build | seconds |
| AWS Athena on raw S3 | ~$6K | 30 s – 5 min |
| Self-managed Elasticsearch | $8K–$15K + ops | sub-second |
| AWS OpenSearch (managed) | $15K–$25K | sub-second |
| Grafana Cloud Loki | ~$15K | seconds |
| Datadog Flex Logs | ~$18K | seconds |
| Datadog Logs (Standard) | ~$75K | sub-second |
| Splunk Cloud | $60K–$250K | sub-second |
| Datadog Log Rehydration | $0 hot + $1.50/GB per query | **hours** |

Two axes at once:

- **Mode choice**: K8s is cheaper than Lambda at 1 TB/day sustained because Lambda compute is priced per second and the indexer runs near-continuously. Lambda wins when the offload is bursty or intermittent.
- **Where the overflow lands**: the closest peer is Datadog Rehydration (bottom row), the archive-and-fetch-back path the Retriever stands in for, without the per-query rehydration fee or the hours-long wait. The hot-analyzer rows are the "keep it all hot instead" baseline, 5×–80× more for the same volume; Athena-on-S3 lands near the Retriever on cost but scans in 30 s – 5 min instead of sub-second.

## Which one fits

| If you're… | Pick |
|---|---|
| Launching a new retriever and want the fewest moving parts | **Lambda** |
| Already running on AWS EKS and want the retriever next to your other workloads | **Kubernetes** |
| Logs already land in Azure Blob Storage, on AKS | **[Azure](azure.md)** |
| Bursty: hours of quiet punctuated by short periods of heavy query activity | **Lambda** |
| Steady: continuous high-throughput ingest across the day | **Kubernetes** |
| Need queries longer than 15 minutes (long-running fetches that pull back large result sets) | **Kubernetes** |
| Want to minimize ops: no cluster, no HPA, no node-sizing | **Lambda** |

## What's identical

- **Same engine image**: built from `pipeline/run-lambda/` (Lambda) or `pipeline/run-quarkus/` (Kubernetes); both wrap the same pipeline binary in a different front-end.
- **Same object storage layout**: raw logs under your chosen source prefix; bloom + reverse-index artifacts under `tenx/{target}/...`. The layout is identical in an S3 bucket and in an Azure Blob container.
- **Same query semantics**: both accept the same [query JSON](../query.md) and produce events + `_DONE.json` markers identically.
- **Same query MCP tools**: [`log10x_retriever_query`](../../mcp/tools/retrieve/retriever-query.md) and [`log10x_retriever_series`](../../mcp/tools/retrieve/retriever-series.md) query either deployment over the same `POST /streamer/query` contract. Install differs by mode: `advise_retriever` emits the Kubernetes/Helm recipe, while the Lambda path is provisioned with the `terraform-aws-tenx-retriever-lambda` module directly (no advisor).

## Switching later

Because the two modes read and write the same layout, you can run both against the same offload during a migration. Stand up Lambda for query-only against your existing Kubernetes-indexed offload, measure, then cut over indexing last, or do the reverse.
