PostHog / PostHog/posthog

chore(cohorts): migrate legacy cohort `groups` field to `filters`

Open
#52,026 0 comments 0 reactions 1 assignee View on GitHub

@patricio-posthog is already working on this.

Since Mar 24, 2026.

enhancement feature/feature-flags team/feature-flags
Dominant language
Python
Stars
39.9k
Forks
3.4k
Avg merge
6h 51m
Merged PRs (30d)
232

Description

Is your feature request related to a problem?

The Cohort model has two fields for storing cohort conditions: the legacy groups (a JSONField(default=list)) and the newer filters (added in migration 0230_cohort_filters, May 2022). The filters field is the canonical source, but ~32,500 cohorts in production (31,688 US, 812 EU) still have data only in groups with no filters populated.

At read time, the properties property (cohort.py:221-284) checks filters first and falls back to converting groups on-the-fly. This conversion handles several legacy formats:

  • Old event-type properties that should be person type
  • Ancient {'key': 'value'} flat dicts
  • Action/event-based groups → behavioral properties

This runtime conversion works, but it means ~32k cohorts pay a per-access conversion cost and the codebase carries multiple legacy format handlers indefinitely.

Additionally, calculate_people_ch() includes groups in its update_fields list even though it never modifies it — a historical artifact that creates confusion (see PR review discussion).

Describe the solution you'd like

A batched data migration that:

  1. For each cohort where filters is empty/null and groups is populated, convert groups to the equivalent filters JSON using the same logic as the properties property
  2. Write the converted filters value while leaving groups intact as a safety net
  3. After validation, clean up calculate_people_ch() to remove groups from update_fields
  4. Eventually remove the runtime groups → properties conversion path and the groups column

The API still allows passing in groups. We probably need to either make that invalid OR automatically convert groups to filters. We may want to add a metric to see how prevalent this is before making a decision.

Describe alternatives you've considered

  • Do nothing: The runtime conversion is cheap (dict manipulation, no DB queries) and works correctly. The main cost is code complexity, not performance.
  • Stop writing groups on new cohorts only: Would prevent growth but not reduce existing legacy data.

Additional context

  • Scale: ~32.5k cohorts total (31,688 US + 812 EU) — manageable for a batched migration
  • Edge case: Some groups entries are in an "invalid state" (no properties, no action_id, no event_id). The current code returns an empty PropertyGroup for these. Migration should flag or skip these.
  • Priority: Low — opportunistic cleanup, not urgent. Good candidate for when someone is already working in the cohort area.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.