Materialization

Materialization pre-computes your query results and stores them in S3. When someone calls your endpoint, PostHog returns the materialized results instead of running the query again - making responses much faster.

When to use materialization

Materialization is ideal when:

  • Your data doesn't need to be real-time - Results are only as fresh as the last sync
  • Your query is expensive - Complex queries with large datasets benefit the most
  • You have high traffic - Avoid repeatedly running the same query

If you need real-time data or frequently update your query, stick with direct execution or use caching instead.

How to enable materialization

  1. Go to your endpoint's Configuration tab
  2. Enable the Materialization toggle
  3. Choose a sync frequency:
    • Every hour - Updates every hour
    • Every 6 hours - Updates four times a day
    • Daily - Updates once per day
    • Weekly - Updates once per week

PostHog will run the first materialization immediately. After that, it syncs on your chosen schedule.

Materialization status

On the endpoint page, you'll see one of these statuses:

  • Completed - Latest materialization succeeded, results are available
  • Running - Materialization is in progress
  • Failed - Materialization encountered an error

If materialization fails, the endpoint falls back to direct execution until the next successful sync.

Limitations

Materialization is not available when:

  • The endpoint has incompatible variables - Only certain variable types are supported. See the compatibility table below.
  • The endpoint is inactive - Only active endpoints and their versions are materialized.

Variable compatibility

Not all variables work with materialization. Compatibility depends on the operator and where the variable is used in the query.

Variable typeSupportedNotes
Equality (=) on columns✅ YesStandard column filters work out of the box
Range (>=, >, <, <=) on timestamp columns✅ YesUses timestamp bucketing to pre-aggregate data
Variables in HAVING clauses❌ NoCannot be materialized
Variables in OR conditions❌ NoCannot be materialized

Timestamp bucketing

When your query uses timestamp range variables (e.g., timestamp >= {variables.start_date} AND timestamp < {variables.end_date}), PostHog uses bucketed materialization.

Instead of materializing a single result set, PostHog pre-aggregates your data into time buckets. At read time, it re-aggregates only the buckets that fall within your actual variable values.

Supported bucket granularities:

  • hour
  • day (default)
  • week
  • month

By default, PostHog uses toStartOfDay to bucket your data. This means each row in the materialized result represents one day of pre-aggregated data.

Configuring bucket size

You can customize the bucket granularity for each timestamp column directly in the Configuration tab. When materialization is enabled and your query has timestamp range variables, a dropdown appears for each timestamp column, letting you select a bucket size:

  • Hour
  • Day
  • Week
  • Month

Smaller buckets give more precise results, while larger buckets produce less granular results.

Bucketed materialization only works with aggregate functions that can be re-aggregated across buckets: count, sum, min, max, and their combinator variants like countIf and sumIf. Functions like avg, uniq, and countDistinct cannot be re-aggregated and are not supported.

How materialization works with execution

When you execute an endpoint:

  1. If materialization is enabled and complete, PostHog returns the materialized results
  2. If materialization is running or failed, PostHog executes the query directly

See Execution for more details on how PostHog chooses between materialized and direct execution.

Community questions

Was this page useful?

Questions about this page? or post a community question.