- Materializations — Run a query against your warehouse, convert the results to a materialization format, and upload to S3
- DuckDB queries — When a user query matches a pre-aggregate, read the materialized data from S3 and execute the query using DuckDB
pre-aggregate stream.
Pre-aggregate materializations
Scheduled jobs materialize warehouse query results and store them on S3:Pre-aggregate queries
When a user query matches a pre-aggregate, the worker serves it using DuckDB against materialized data on S3 — without hitting your data warehouse:Prerequisites
- A valid Enterprise license key
- An S3-compatible bucket for materialized data (AWS S3, GCS, MinIO)
- NATS and warehouse workers enabled (see NATS workers overview)
Example configuration
A complete Helm values configuration with NATS, warehouse worker, and pre-aggregate worker:
See the overview for details on JetStream configuration options.
S3 storage configuration
Pre-aggregates require a dedicated S3 bucket separate from your main Lightdash results cache bucket. This prevents query history cleanup from deleting active materialization files.S3_ENDPOINT and S3_FORCE_PATH_STYLE are inherited from your base S3 configuration. Access keys fall back to the base S3 credentials if not set separately.
- AWS S3
- Google Cloud Storage
- MinIO
Configuration reference
All configuration is set through your Helmvalues.yaml under preAggregateNatsWorker:
Scaling
Resources
Pre-aggregate workers need significantly more resources than warehouse workers because they run DuckDB in-process for both materializing data and serving queries against materialized data.
DuckDB memory tuning
DuckDB runs inside the pre-aggregate worker process. There are two types of DuckDB instances:
By default, the shared query instance has no memory cap. Under concurrent load, this can cause OOM kills. Set a limit:
Optional environment variables
These can be set viaextraEnv or configMap if you need to override the defaults:
Troubleshooting
Pre-aggregate queries hitting the warehouse instead of DuckDB
- Verify that
PRE_AGGREGATES_ENABLEDis set to"true"on the pre-aggregate worker pod - Verify that
PRE_AGGREGATES_PARQUET_ENABLEDis set to"true"on the pre-aggregate worker pod - Confirm the pre-aggregate worker pod is running and healthy
- Check that an active materialization exists in Project Settings > Pre-aggregates
- Review query matching rules — see monitoring and debugging
Worker OOM kills
Pre-aggregate workers run DuckDB which can consume significant memory:- Set
PRE_AGGREGATE_DUCKDB_QUERY_MEMORY_LIMIT(e.g.,3GB) to cap DuckDB memory - Increase the worker’s memory request and limit
- Reduce
concurrencyto limit parallel DuckDB queries
Materialization failures
Common causes:- S3 access denied — Verify
PRE_AGGREGATE_RESULTS_S3_*credentials and bucket permissions - Warehouse timeout — Large materializations may exceed warehouse query timeout limits
- Disk pressure — Materialization writes temporary files to local disk. Increase ephemeral storage if you see evictions.
- Too many rows — Materializations should not contain very large datasets. We recommend keeping materializations under 100,000 rows for optimal performance. You can use
max_rowsin your pre-aggregate definition or thePRE_AGGREGATES_MAX_ROWSenvironment variable to enforce a limit.