Skip to main content
PostHog uses a monorepo structure to organize all product code, services, and shared utilities in a single repository. This document explains the high-level directory layout.

Directory Overview

Core Directories

posthog/ - Legacy Monolith

The original Django application containing:
  • Django REST Framework views
  • API serializers and validators
  • URL routing for legacy endpoints
  • Authentication and permissions
  • Core Django ORM models
  • Team, User, Organization
  • Legacy product models (being migrated to products/)
  • HogQL query runners
  • Query execution and optimization
  • AST-based query composition
  • ClickHouse query builders
New code should be added to products/ rather than the legacy posthog/ directory. The monolith is being incrementally refactored into product-specific apps.

products/ - Product Apps

Each product is a self-contained vertical slice with its own backend and frontend. Examples:
  • feature_flags/ - Feature flags and rollouts
  • experiments/ - A/B testing and experimentation
  • session_replay/ - Session recording and playback
  • data_warehouse/ - External data integration
  • error_tracking/ - Error monitoring and alerts
Benefits of the product structure:
  • Clear ownership boundaries
  • Independent testing with Turborepo
  • Isolated dependencies
  • Easier to understand and maintain
See the Product Architecture page for details on the product pattern.

services/ - Independent Services

Services are standalone deployments with their own domain logic:
Services are NOT:
  • Shared infrastructure (that’s platform/)
  • User-facing products (that’s products/)
  • Cross-cutting utilities (that’s common/)

common/ - Shared Code

Utilities and libraries used across products:
1

hogli

Developer CLI for scaffolding and tooling:
2

hogql_parser

HogQL parser and AST utilities for query parsing
3

Other Utilities

  • Tailwind config
  • Storybook setup
  • Plugin transpiler

frontend/ - Main Frontend

The main React application:
Product-specific frontend code lives in products/<product>/frontend/, not in the main frontend/ directory.

Aspirational Directories

These directories represent the future architecture but don’t fully exist yet:

platform/ (Aspirational)

Shared platform code for cross-cutting concerns:
Why platform must not call product code:If platform imports product code, it becomes a hidden orchestrator that must know which products exist, route events to product logic, and accumulate product-specific conditionals. This destroys the “platform is foundational” property and creates circular dependencies.

tools/ (Aspirational)

Developer tooling that isn’t imported by runtime code:
  • CLIs, linters, formatters
  • Code generators and scaffolding
  • Build scripts and utilities
Currently common/hogli/ serves this purpose.

File Organization Principles

Where to Put New Code

1

Product-Specific Features

Add to products/<product>/backend/ or products/<product>/frontend/
2

Shared Business Logic

If it’s truly cross-product, consider creating a new product or service
3

Infrastructure Utilities

Add to common/ (eventually migrate to platform/)
4

Developer Tools

Add to common/hogli/ or create standalone tool

Import Rules

  • Products should NOT import from each other’s internals
  • Use product facades for cross-product communication
  • Platform/common code must NOT import from products
  • Services are completely independent
Import boundaries are enforced by tach - the CI will fail if you violate these rules.

Migration Strategy

PostHog is gradually migrating from the monolith to the product structure:
  1. New features → Always create in products/
  2. Legacy code → Migrate when making significant changes
  3. Shared code → Extract to common/ or create facades
  4. Enterprise features → Migrate from ee/ to products/

Working with the Monorepo

Finding Code

Running Tests

Checking Boundaries

Next Steps

Product Architecture

Deep dive into the product pattern

Development Setup

Set up your local environment