Manual development setup
Contents
Manual setup
This documentation is deprecated, and likely not up to date. Please use the Flox-based instant setup instead.
1. Spin up external services
In this step we will start all the external services needed by PostHog to work.
First, append line 127.0.0.1 kafka clickhouse clickhouse-coordinator objectstorage and line ::1 kafka clickhouse clickhouse-coordinator objectstorage to /etc/hosts. Our ClickHouse and Kafka data services won't be able to talk to each other without these mapped hosts.
You can do this with:
If you are using a newer (>=4.1) version of Podman instead of Docker, the host machine's
/etc/hostsis used as the base hosts file for containers by default, instead of container's/etc/hostslike in Docker. This can make hostname resolution fail in the ClickHouse container, and can be mended by settingbase_hosts_file="none"incontainers.conf.
Now, start the Docker Compose stack:
Friendly tip 1: If you see
Error while fetching server API version: 500 Server Error for http+docker://localhost/version:, it's likely that Docker Engine isn't running.
Friendly tip 2: If you see "Exit Code 137" anywhere, it means that the container has run out of memory. In this case you need to allocate more RAM in OrbStack settings.
Friendly tip 3: On Linux, you might need
sudo– see Docker docs on managing Docker as a non-root user. Or look into Podman as an alternative that supports rootless containers.
Friendly tip 4: If you see
Error: (HTTP code 500) server error - Ports are not available: exposing port TCP 0.0.0.0:5432 -> 0.0.0.0:0: listen tcp 0.0.0.0:5432: bind: address already in use, you have Postgres already running somewhere. Trydocker compose -f docker-compose.dev.ymlfirst, alternatively runlsof -i :5432to see what process is using this port.
Second, verify via docker ps and docker logs (or via the OrbStack dashboard) that all these services are up and running. They should display something like this in their logs:
Friendly tip 1: Kafka is currently the only x86 container used, and might segfault randomly when running on ARM. Restart it when that happens.
Friendly tip 2: Checking the last Clickhouse log could show a
get_mempolicy: Operation not permittedmessage. However, it shouldn't affect the app startup - checking the whole log should clarify that Clickhouse started properly. To double-check you can get into the container and run a basic query.Terminal
Finally, install Postgres locally. Even if you are planning to run Postgres inside Docker, we need a local copy of Postgres (version 11+) for its CLI tools and development libraries/headers. These are required by pip to install psycopg2.
On macOS:
Terminal
This installs both the Postgres server and its tools. DO NOT start the server after running this.
On Debian-based Linux:
Terminal
This intentionally only installs the Postgres client and drivers, and not the server. If you wish to install the server, or have it installed already, you will want to stop it, because the TCP port it uses conflicts with the one used by the Postgres Docker container.
On Linux, it's recommended to disable Postgres service by default, to ensure no port conflict arises. If postgres is already running on the port 5432, you can confirm it by checking the port, and then kill it manually.
On Linux you often have separate packages: postgres for the tools, postgres-server for the server, and libpostgres-dev for the psycopg2 dependencies. Consult your distro's list for an up-to-date list of packages.
2. Prepare the frontend
- Install nvm, with
brew install nvmor by following the instructions at https://github.com/nvm-sh/nvm. If using fish, you may instead prefer https://github.com/jorgebucaran/nvm.fish.
After installation, make sure to follow the instructions printed in your terminal to add NVM to your $PATH. Otherwise the command line will use your system Node.js version instead.Install the latest Node.js 22 (the version used by PostHog in production) with
nvm install 22. You can start using it in the current shell withnvm use 22.Install pnpm by running
corepack enableand then runningcorepack prepare pnpm@10 --activate. Validate the installation withpnpm --version.Install Node packages by running
pnpm i.Run
pnpm --filter=@posthog/frontend typegen:writeto generate types for Kea state management logics used all over the frontend.
The first time you run typegen, it may get stuck in a loop. If so, cancel the process (
Ctrl+C), discard all changes in the working directory (git reset --hard), and runpnpm typegen:writeagain. You may need to discard all changes once more when the second round of type generation completes.
3. Prepare plugin server
- Install the
brotlicompression library andruststable viarustup:
On macOS:
TerminalOn Debian-based Linux:
Terminal
- Run
pnpm --filter=@posthog/plugin-server installto install all required packages. We'll actually run the plugin server in a later step.
Note: If you face an error like
ld: symbol(s) not found for architecture arm64, most probably your openssl build flags are coming from the wrong place. To fix this, run:
Note: If you face an error like
import gyp # noqa: E402, most probably need to installpython-setuptools. To fix this, run:
Troubleshooting plugin server issues: If you encounter problems starting up the plugin server, try these debugging steps:
4. Prepare the Django server
Install a few dependencies for SAML to work. If you're on macOS, run the command below, otherwise check the official xmlsec repo for more details.
On macOS:
TerminalIf installing
xmlsecdoesn't work, try updating macOS to the latest version (Sonoma).On Debian-based Linux:
Terminal
Install Python 3.12.
On macOS, you can do so with Homebrew:
brew install python@3.12.On Debian-based Linux:
Terminal
Make sure when outside the venv to always use python3 instead of python, as the latter may point to Python 2.x on some systems. If installing multiple versions of Python 3, such as by using the deadsnakes PPA, use python3.12 instead of python3.
You can also use pyenv if you wish to manage multiple versions of Python 3 on the same machine.
- Install
uv
uv is a very fast tool you can use for python virtual env and dependency management. See https://docs.astral.sh/uv/. Once installed you can prefix any pip command with uv to get the speed boost.
Create the virtual environment with the right Python version, and install dependencies - all in one with this command:
TerminalFriendly tip: Creating an env could raise a
Failed to parsewarning related topyproject.toml. However, you should still see theActivate with:line at the very end, which means that your env was created successfully.Activate the virtual environment:
TerminalInstall requirements with uv
If your workstation is an Apple Silicon Mac, the first time you install Python packages, you must set custom OpenSSL headers:
TerminalFriendly tip: If you see
ERROR: Could not build wheels for xmlsec, refer to this issue.These will be used when installing
grpcioandpsycopg2. After doing this once, and assuming nothing changed with these two packages, next time simply run:Terminal
5. Prepare databases
We now have the backend ready, and Postgres and ClickHouse running – these databases are blank slates at the moment however, so we need to run migrations to e.g. create all the tables:
Friendly tip 1: The error
fe_sendauth: no password suppliedconnecting to Postgres happens when the database is set up with a password and the user:pass isn't specified inDATABASE_URL. Tryexport DATABASE_URL=postgres://posthog:posthog@localhost:5432/posthog.
Friendly tip 2: You may run into
psycopg2errors while migrating on an ARM machine. Try out the steps in this comment to resolve this.
Friendly tip 3: When migrating, make sure the containers are running (detached or in a separate terminal tab).
6. Start PostHog
Now start all of PostHog (backend, worker, plugin server, and frontend – simultaneously) with one of:
Note: This command uses mprocs to run all development processes in a single terminal window. It will be installed automatically for macOS, while for Linux you can install it manually (
cargoornpm) using the official repo guide.
Friendly tip: If you get the error
Configuration property "enable.ssl.certificate.verification" not supported in this build: OpenSSL not available at build time, make sure your environment is using the rightopensslversion by setting those environment variables, and then run./bin/startagain.
Open http://localhost:8010 to see the app.
Note: The first time you run this command you might get an error that says "layout.html is not defined". Make sure you wait until the frontend is finished compiling and try again.
To get some practical test data into your brand-new instance of PostHog, run DEBUG=1 ./manage.py generate_demo_data. For a list of useful arguments of the command, run DEBUG=1 ./manage.py generate_demo_data --help.
Friendly Tip The first time you run the app, you can log in with a test account: user:
test@posthog.compwd:12345678.
7. Develop
This is it – you should be seeing the PostHog app at http://localhost:8010.
You can now change PostHog in any way you want. See Project structure for an intro to the repository's contents. To commit changes, create a new branch based on master for your intended change, and develop away.