docs/published/handbook/engineering/flox-multi-instance-workflow.md
This guide explains how to create isolated PostHog development environments using Flox and Git worktrees for seamless branch switching.
This guide builds on the developing locally setup. You should have Flox installed and be able to run
hogli start(PostHog's developer CLI, available inside the Flox environment) before proceeding.
Key Benefits:
hogli start command works in each worktreeImportant: Only one PostHog instance (
hogli start) can run at a time since they all use the same ports. The workflow focuses on quickly stopping one instance and starting another.
brew install ghbrew install jqbrew install direnvBy default, worktrees are created in ~/.worktrees/posthog/. You can customize this location by setting the POSTHOG_WORKTREE_BASE environment variable:
# In your shell profile (~/.zshrc or ~/.bashrc)
export POSTHOG_WORKTREE_BASE="/path/to/your/preferred/location"
For example:
export POSTHOG_WORKTREE_BASE="$HOME/code/worktrees"
# Worktrees will be created in ~/code/worktrees/<branch-name>
In all these examples, replace ~/dev/posthog/posthog with your local path to the PostHog repo.
# Install dependencies
brew install direnv gh jq
# Add direnv hook to your shell (~/.zshrc or ~/.bashrc)
eval "$(direnv hook zsh)" # or bash
# Add the phw function for auto-cd functionality
echo 'source ~/dev/posthog/posthog/bin/phw' >> ~/.zshrc # or ~/.bashrc
# Reload your shell
source ~/.zshrc # or ~/.bashrc
# Verify setup in main repo
cd ~/dev/posthog/posthog
flox activate
# You should see Flox environment activate and uv sync run
phwAfter setup, use the phw command for everything:
# creates branch haacked/new-feature and worktree haacked/new-feature off of master
phw create haacked/new-feature
# You're now IN the worktree with Flox activated!
hogli start
# Access at http://localhost:8010
# Or specify a different base branch
phw create haacked/new-feature master
phw checkout haacked/new-feature
# Creates worktree for existing branch, Flox activated!
hogli start
# Access at http://localhost:8010
phw switch haacked/new-feature
# Switches to already created worktree, Flox activated!
hogli start
# Access at http://localhost:8010
phw pr 12345
# Fetched PR, switched to worktree, ready to test!
hogli start
# Access at http://localhost:8010
# 9:00 AM - Start working on new dashboard
phw create haacked/analytics-dashboard
hogli migrations:run # Run migrations
hogli start # Start development
# Work on feature at http://localhost:8010
# 10:30 AM - Urgent production bug!
# Stop current PostHog instance first
# Ctrl+C to stop hogli start
phw checkout master
# Already in main worktree with Flox activated
git pull origin master
hogli start # Start development
# Fix bug, test at http://localhost:8010
# 11:00 AM - Review teammate's PR
# Stop current instance first
phw pr 5678
# Automatically fetches PR and switches to it
hogli start
# Review at http://localhost:8010
# 2:00 PM - Back to feature work
# Stop current instance and switch back
phw switch haacked/analytics-dashboard
# You may see interactive prompt - press Enter to skip nesting, or run 'exit' first
hogli start # Continue where you left off
# 5:00 PM - Cleanup
phw list # See all worktrees
phw remove pr-5678-teammate # Done with PR review
Since you can only run one PostHog instance at a time, the workflow focuses on quickly switching between isolated environments:
# Create isolated worktrees for different tasks
phw create haacked/feature-analytics
phw checkout bugfix/login-issue
phw pr 1234
# Work on feature
phw switch haacked/feature-analytics
hogli start # Work on feature
# Stop and switch to bug fix
# Ctrl+C to stop
phw switch bugfix/login-issue
hogli start # Switch to bug fix work
# Stop and switch to PR review
# Ctrl+C to stop
phw switch pr-1234-teammate
hogli start # Review PR
# See all your worktrees
phw list
# Output:
# All PostHog Worktrees:
#
# Branch Path Location
# ------ ---- --------
# haacked/improved-workflow /Users/username/dev/posthog/posthog other
# haacked/analytics-dashboard /Users/username/.worktrees/posthog/haacked/... current
# main /Users/username/.worktrees/posthog/main current
# pr-5678-teammate /Users/username/.worktrees/posthog/pr-5678-... current
#
# Legend:
# current = in current worktree base (/Users/username/.worktrees/posthog)
# other = in different location
# Remove when done (works regardless of location)
phw remove pr-5678-teammate
The phw list and phw remove commands work with all your PostHog worktrees, regardless of where they were created. This is helpful if you:
POSTHOG_WORKTREE_BASE setting after creating some worktreesExample scenario:
# You had worktrees in the old location
ls ~/.worktrees/posthog/
# old-feature/ pr-1234-teammate/
# You changed your worktree base
export POSTHOG_WORKTREE_BASE="$HOME/dev/worktrees"
# phw list still shows ALL worktrees
phw list
# Shows both old location worktrees AND new location worktrees
# phw remove works with any worktree location
phw remove pr-1234-teammate # Works even though it's in old location!
This uses Git's native worktree tracking (git worktree list) rather than trying to guess paths.
phw create <branch> [base-branch] # Create new branch & worktree (defaults to master)
phw checkout <branch> # Create worktree for existing branch
phw switch <branch> # Switch to existing worktree
phw pr <number> # Checkout PR in worktree
phw remove <branch> # Remove worktree
phw list # List all worktrees
hogli start command in each worktree.envrc: Automatically activates Flox when you enter any worktree directory.flox/env/manifest.toml and Python venvuv sync uses its own caching, so dependencies are efficiently sharedphw function: Provides auto-cd functionality and smart tab completionphw list and phw remove use Git's authoritative worktree tracking, working with worktrees from any locationphw create branch → creates worktree → copies .envrc → cd to worktree →
direnv detects .envrc → activates Flox → runs uv sync → ready to code!
When you switch between worktrees while already in a Flox environment, you'll see an interactive prompt to prevent unexpected nested environments:
⚠️ About to activate Flox environment in worktree while already in environment for:
/Users/username/dev/posthog/posthog
Continue with nested activation? (y/N):
Your options:
exit first to cleanly switch environmentsexit commands later)exit and retryBest practice: When switching between worktrees, exit your current Flox environment first:
# Currently in main repo with Flox active
exit # Leave current Flox environment
cd ~/.worktrees/posthog/my-branch # Switch to worktree
# Flox activates cleanly without nesting prompt
The phw function includes smart tab completion:
phw create <TAB> - Suggests "haacked/" prefixphw checkout <TAB> - Shows all available branchesphw remove <TAB> - Shows removable worktrees# Clean up unused worktrees
git worktree prune
# See current worktrees
phw list
# Check Flox environment status
flox list
# See what's installed in current environment
flox search --installed
# Check current worktrees
git worktree list
# Make sure direnv is allowed in the worktree
phw switch your-branch
direnv allow
# Check direnv is properly hooked into your shell
which direnv # Should show /opt/homebrew/bin/direnv or similar
echo $DIRENV_DIR # Should show something when in a direnv directory
# Trust the environment
flox activate --trust
# Or reinstall Flox environment
rm -rf .flox
cp -r ~/dev/posthog/posthog/.flox/env .flox/
flox activate
# Make sure you've sourced the phw script
source ~/dev/posthog/posthog/bin/phw
# Add it permanently to your shell profile
echo 'source ~/dev/posthog/posthog/bin/phw' >> ~/.zshrc
# Force reinstall in Flox environment
flox activate -- uv sync --reinstall
Problem: You see the interactive prompt every time you switch directories
Solution: This is expected behavior when switching between worktrees. Choose the best approach:
# Option 1: Skip nesting (recommended)
# Press Enter or 'n' when prompted, then:
exit # Leave current environment
phw switch your-branch # Switch cleanly and consistently
# Option 2: Allow nesting (if you prefer)
# Type 'y' when prompted, then remember to exit multiple times later
# Option 3: Use phw commands (avoids the prompt)
phw checkout your-branch # Automatically handles switching
# Remove a specific worktree
phw remove haacked/old-feature
# Clean up unused worktree references (safe to run)
git worktree prune
For a complete one-time setup, run:
# For zsh users
brew install direnv gh jq && \
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc && \
echo 'source ~/dev/posthog/posthog/bin/phw' >> ~/.zshrc && \
source ~/.zshrc && \
echo "✅ Setup complete! You can now use 'phw' commands."
# For bash users
brew install direnv gh jq && \
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc && \
echo 'source ~/dev/posthog/posthog/bin/phw' >> ~/.bashrc && \
source ~/.bashrc && \
echo "✅ Setup complete! You can now use 'phw' commands."
After setup, you're ready to use commands like:
phw create haacked/feature (create from master)phw create haacked/feature my-branch (create from my-branch)phw checkout my-branchphw pr 12345