Directory Overview
Core Directories
posthog/ - Legacy Monolith
The original Django application containing:
API Layer (posthog/api/)
API Layer (posthog/api/)
- Django REST Framework views
- API serializers and validators
- URL routing for legacy endpoints
- Authentication and permissions
Models (posthog/models/)
Models (posthog/models/)
- Core Django ORM models
- Team, User, Organization
- Legacy product models (being migrated to
products/)
Query Layer (posthog/queries/)
Query Layer (posthog/queries/)
- 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 rolloutsexperiments/- A/B testing and experimentationsession_replay/- Session recording and playbackdata_warehouse/- External data integrationerror_tracking/- Error monitoring and alerts
- Clear ownership boundaries
- Independent testing with Turborepo
- Isolated dependencies
- Easier to understand and maintain
services/ - Independent Services
Services are standalone deployments with their own domain logic:
- 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:
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
common/hogli/ serves this purpose.
File Organization Principles
Where to Put New Code
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:- New features → Always create in
products/ - Legacy code → Migrate when making significant changes
- Shared code → Extract to
common/or create facades - Enterprise features → Migrate from
ee/toproducts/
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