How to run a GitHub project on your computer, language by language
Clone it, check its root files, install the pinned runtime and dependencies, set up .env and start it. Commands and fixes for Node, Python, Go, Rust, Ruby, PHP.
By the pyrovue team · · 11 min read
To run a GitHub project locally, clone it (or download the ZIP), look at the files in its root folder to see what kind of project it is, install the runtime version it pins, install its dependencies with the package manager its lockfile belongs to, copy .env.example to .env, then run its start command and open the address it prints. For a typical Node.js project that is git clone, npm ci and npm run dev. For a Python project it is a virtual environment, pip install -r requirements.txt and the start command from the README.
The commands are rarely the hard part. The hard part is knowing which ones someone else's project needs, and what to do when the third one fails. This guide covers both, for Node.js, Python, Go, Rust, Ruby, PHP and Docker projects, with fixes for the errors that stop most first runs.
If you'd rather not install anything, running a GitHub project without downloading it compares the browser-based options.
Clone the repository or download the ZIP
Cloning is the better default: you get the history, the branches and git pull for updates. GitHub's cloning guide covers HTTPS, SSH and the GitHub CLI.
git clone https://github.com/OWNER/REPO.git
cd REPO
For a large repository, --depth 1 fetches only the latest commit, and --branch picks a release: git clone --depth 1 --branch v2.1.0 https://github.com/OWNER/REPO.git.
Without Git, click Code, then Download ZIP. You lose the history, submodule folders come out empty, and Git LFS files arrive as small pointer files unless the owner turned on LFS in archives. A clone skips those two by default as well:
git submodule update --init --recursive # the root has a .gitmodules file
git lfs install && git lfs pull # .gitattributes has filter=lfs lines
On Windows, projects with shell scripts, Makefiles or symlinks behave far better inside WSL. Clone them with Git inside WSL, into the Linux filesystem (~/code, not /mnt/c/...), which also avoids /bin/bash^M: bad interpreter errors from Windows line endings.
Work out what kind of project it is
The files in the root folder tell you the language, the package manager and usually the start command. Read the lockfile first: it decides the package manager, and installing with a different one ignores the versions the maintainers tested.
| File in the root | Project type | Install | Start (confirm in the README) |
|---|---|---|---|
package.json and package-lock.json | Node.js, npm | npm ci | npm run dev or npm start |
pnpm-lock.yaml | Node.js, pnpm | pnpm install | pnpm dev |
yarn.lock | Node.js, Yarn | yarn install | yarn dev |
bun.lock or bun.lockb | Bun | bun install | bun run dev |
requirements.txt | Python, pip | pip install -r requirements.txt | python app.py, flask --app app run, uvicorn main:app --reload |
pyproject.toml and uv.lock | Python, uv | uv sync | uv run <command> |
pyproject.toml and poetry.lock | Python, Poetry | poetry install | poetry run <command> |
manage.py | Django | one of the Python rows | python manage.py migrate, then python manage.py runserver |
go.mod | Go | go mod download | go run . or go run ./cmd/<name> |
Cargo.toml | Rust | cargo build | cargo run |
Gemfile | Ruby (Rails if config/routes.rb exists) | bundle install | bin/rails server or bin/dev |
composer.json | PHP (Laravel if an artisan file exists) | composer install | php artisan serve |
pom.xml or build.gradle | Java or Kotlin | ./mvnw package or ./gradlew build | ./mvnw spring-boot:run or ./gradlew bootRun (Spring Boot) |
Dockerfile | Container image | docker build -t app . | docker run --rm -p 8080:8080 app |
compose.yaml or docker-compose.yml | Several services | docker-compose up | |
Makefile, justfile, Taskfile.yml | Task runner around the above | read the targets | often make dev or make run |
.devcontainer/devcontainer.json | Dev container | VS Code or Codespaces builds it | its postCreateCommand is the setup |
A pnpm-workspace.yaml, turbo.json, nx.json or a workspaces field in package.json means a monorepo: install once from the root, then start the app with the root script or something like pnpm --filter web dev. A repo with frontend/ and backend/ folders usually needs both started, in two terminals.
Read the README's setup section critically
READMEs go stale faster than code. Before following one line by line:
- Check who it's written for. "Installation:
npm install some-lib" tells library users how to add the package to their app. To run the repository itself, look for a "Development" or "Running locally" section, or aCONTRIBUTING.md. - Compare it with the CI workflow. Files in
.github/workflows/run on every push, so they show a setup that worked recently: the runtime version (node-version,python-version), the install command, any database service and the environment variables the tests need. When the README and CI disagree, trust CI. - Read the Dockerfile even if you won't use Docker. Its
apt-get installlines name the system libraries the project needs, which is what you'll be missing when a native build fails. - List the scripts instead of guessing.
npm runwith no arguments prints the scripts inpackage.json;just --listandtask --listdo the same for a justfile or Taskfile, andgrep -E '^[A-Za-z0-9_.-]+:' Makefilelists Makefile targets. - Check the last commit date and recent issues. A project last touched in 2021 wants the Node or Python of 2021, and an open "fails to build" issue often has the fix in its comments.
Install the runtime version the project expects
When an older project won't run, a runtime that's too new is the usual cause. Look for these pins:
| Language | Where the version is pinned |
|---|---|
| Node.js | .nvmrc, .node-version, engines.node and packageManager in package.json |
| Python | .python-version, runtime.txt, requires-python in pyproject.toml |
| Go | the go and toolchain lines in go.mod |
| Rust | rust-toolchain.toml |
| Ruby | .ruby-version, the ruby line in Gemfile |
| Several | .tool-versions, mise.toml |
Install that version with a version manager rather than changing your system one:
nvm install && nvm use # Node, reads .nvmrc
fnm use --install-if-missing # Node, reads .nvmrc and .node-version
pyenv install # Python, reads .python-version
uv reads .python-version and downloads that Python the first time a command needs it, so uv sync or uv venv is usually enough. mise covers every language from one tool. It reads mise.toml and .tool-versions directly, but reads .nvmrc and .python-version only for tools you enable:
mise settings add idiomatic_version_file_enable_tools node
mise install
Go 1.21 and later switch to the toolchain go.mod asks for, downloading it if needed, and rustup picks up rust-toolchain.toml on its own. If package.json has a packageManager field such as "pnpm@9.15.0", use that exact version. Corepack handles this, but Node.js 25 and later no longer bundle it, so run npm install -g corepack and then corepack enable.
With no pin at all, start with the current LTS (nvm install --lts) and check the CI matrix for the versions the project is tested on.
Install dependencies and run it, language by language
Node.js
npm ci # exact versions from package-lock.json
npm run dev # or npm start: check the "scripts" block
npm ci fails when package.json and the lockfile disagree, which tells you the repo is inconsistent before you debug anything else. Use npm install when there is no lockfile. Arguments after -- reach the underlying tool, so npm run dev -- --port 3001 moves a Vite server. Recent pnpm versions don't run dependencies' build scripts until you approve them and stop the install with a list: run pnpm approve-builds and approve the packages you trust.
Python
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
python -m pip install -r requirements.txt
uv does the same faster and fetches the right Python. uv run then runs any command inside the environment:
uv sync # pyproject.toml projects
uv venv && uv pip install -r requirements.txt # requirements.txt projects
uv run pytest
Poetry projects use poetry install and poetry run. Requirements sometimes come in pieces (requirements-dev.txt, requirements/base.txt), and pip install -e ".[dev]" installs a pyproject.toml project with its development extras. Then start it the way the framework expects: python manage.py runserver for Django (after migrate), flask --app app run for Flask, uvicorn main:app --reload for FastAPI, streamlit run app.py for Streamlit.
Go, Rust, Ruby and PHP
go run . # Go; or go run ./cmd/server
cargo run # Rust; in a workspace, cargo run -p <crate>
bundle install # Ruby on Rails
bin/rails db:prepare
bin/rails server # or bin/dev when there's a Procfile.dev
composer install # PHP (Laravel)
cp .env.example .env
php artisan key:generate
php artisan migrate
php artisan serve
Rails and Laravel apps often have a JavaScript front end too, so run npm install if there's a package.json. Many Rails apps include bin/setup, which runs the whole sequence.
Docker and Compose
A Dockerfile lets you skip installing runtimes:
docker build -t app .
docker run --rm -p 8080:8080 app # use the port the Dockerfile EXPOSEs
For a Compose file, docker-compose up --build starts every service. Docker Desktop accepts that hyphenated form; on Linux installs that only have the Compose plugin, type it as a subcommand of docker, with a space where the hyphen is. A useful middle ground is to start only the database from the Compose file and run the app natively, so code changes reload without rebuilding an image.
Set up .env, start the app and find the port
-
Copy the template:
cp .env.example .env. It may be called.env.sample,.env.templateor.env.local.exampleinstead (Next.js reads.env.local). -
Fill in only what you need. Database URLs usually work as written once the database is running, keys for optional features (payments, email, analytics) can often stay blank, and secrets such as
SECRET_KEYjust need a random value fromopenssl rand -hex 32. -
With no template, find the variables the code reads:
grep -rhoE 'process\.env\.[A-Z0-9_]+' --exclude-dir=node_modules . | sort -u grep -rhoE "os\.(environ|getenv)[^A-Z]*[A-Z0-9_]+" --exclude-dir=.venv . | sort -u -
Start the app and read its output, since dev servers print their address. The usual defaults:
Framework Default port Next.js, Nuxt, Rails 3000 Vite (React, Vue, SvelteKit) 5173 Angular 4200 Django, FastAPI with uvicorn, Laravel 8000 Flask 5000 Streamlit 8501 Gradio 7860 To see what is actually listening, run
lsof -iTCP -sTCP:LISTEN -n -Pon macOS or Linux, ornetstat -ano | findstr LISTENINGon Windows. -
Run the tests (
npm test,pytest,go test ./...,cargo test,bin/rails test,php artisan test). They exercise the database and environment variables faster than clicking around. If some fail on a fresh clone, compare with the latest run on the repository's Actions tab before blaming your setup.
Why a GitHub project won't run: common errors and fixes
Wrong Node or Python version
npm warn EBADENGINE Unsupported engine, Yarn's The engine "node" is incompatible with this module or a SyntaxError on modern syntax mean the runtime doesn't match. Two well-known errors come from a runtime that is too new: error:0308010C:digital envelope routines::unsupported is webpack 4 on Node 17 or later, and No module named 'distutils' is an older package on Python 3.12, which removed distutils. Install the pinned version. As stopgaps, NODE_OPTIONS=--openssl-legacy-provider gets old webpack builds going, and pip install setuptools restores a distutils shim.
Missing compilers and native headers
When a package has no prebuilt binary for your platform and runtime version, the installer compiles it and needs a compiler plus the library's headers. Typical messages: gyp ERR! find Python, fatal error: Python.h: No such file or directory, pg_config executable not found, mysql_config not found and, on Windows, Microsoft Visual C++ 14.0 or greater is required.
sudo apt install build-essential python3-dev pkg-config libpq-dev default-libmysqlclient-dev # Debian, Ubuntu
xcode-select --install # macOS compilers; then brew install the library the error names
On Windows, install Visual Studio Build Tools with the "Desktop development with C++" workload. For Postgres in Python, psycopg2-binary skips the build for local use. Often the cleanest fix is the pinned runtime version, because prebuilt binaries exist for the versions the project was tested on.
Port already in use
Error: listen EADDRINUSE: address already in use :::3000 (Node) or OSError: [Errno 98] Address already in use (Python on Linux, Errno 48 on macOS) means another process holds the port. lsof -i :3000 shows its PID and kill <PID> stops it. Or move the app: PORT=3001 npm start (if the app reads PORT), npm run dev -- --port 3001, python manage.py runserver 8001. On macOS, AirPlay Receiver listens on port 5000, Flask's default, so use flask --app app run --port 5001 or turn AirPlay Receiver off in System Settings.
Missing environment variables
Environment variable not found: DATABASE_URL (Prisma), KeyError: 'SECRET_KEY', Django's ImproperlyConfigured, or an app that starts and fails on the first request. Create .env from the template. If the app doesn't load .env itself (no dotenv or python-dotenv among its dependencies), export it into your shell with set -a; source .env; set +a.
A module imported under another name
In Python the import name and the package name often differ, so ModuleNotFoundError: No module named 'cv2' means the requirements file is incomplete, and pip install cv2 won't fix it. Install the real package:
| Import | Package to install |
|---|---|
cv2 | opencv-python (opencv-python-headless on servers) |
PIL | Pillow |
yaml | PyYAML |
sklearn | scikit-learn |
bs4 | beautifulsoup4 |
dotenv | python-dotenv |
Database not running
connect ECONNREFUSED 127.0.0.1:5432, connection to server at "localhost" (127.0.0.1), port 5432 failed or Can't connect to MySQL server mean the app expects a database you haven't started. Start it from the Compose file if there is one, then run the migrations:
docker-compose up -d db # use the service name from the Compose file
npx prisma migrate dev # or python manage.py migrate, bin/rails db:prepare, php artisan migrate
Redis on port 6379 works the same way. Check that the user, password and database name in DATABASE_URL match the Compose file's environment block.
Is it safe to run someone else's GitHub project?
Everything in this guide runs with your user account's permissions, and more runs than the app itself. npm install runs the preinstall, install and postinstall scripts of every dependency, pip runs a package's build code when it installs from source, and a Makefile or a curl ... | sh line in a README can do anything. Code running as you can read ~/.ssh, cloud credentials and tokens in your shell environment.
- Read the
scriptsblock, the Makefile and any setup script before running them. npm ci --ignore-scriptsskips dependency scripts, though packages with native builds then won't work. pnpm blocks dependency build scripts until you allow them.- Run code you don't trust in a container or a VM, not in your everyday user session.
Is it safe to run code from GitHub covers the warning signs in more depth, and running untrusted code in a box covers keeping it off your laptop entirely.
The shortcut: run it in a box
pyrovue automates most of this guide. Paste a GitHub link (a repo URL, owner/name, a branch or a pull request) into pyrovue's repo runner and it starts the project in an isolated Linux container, a box. It reads the lockfiles, version pins, README setup sections, Dockerfile, Compose services, Makefile targets and .env templates (filled with safe placeholders), installs and starts the app, and gives you a live preview with a terminal and the setup log. A box starts in about two seconds and most repos are running in about a minute. When a step fails, repair rules cover the failures above (wrong Node or Python version, native headers, cv2 and PIL, missing environment variables, port clashes) and retry. Postgres, MySQL and Redis from a Compose file run inside the box.
The limits: no Docker inside boxes, no GPUs, and notebook-only repos aren't opened automatically. The free Hobby plan gives 20 box-hours a month on 2 vCPU and 4 GB, with no card. If you maintain a repo that pyrovue guesses wrong, a pyrovue.json file in the root sets the commands explicitly:
{"setup": ["pnpm install", "pnpm db:migrate"], "start": "pnpm dev", "port": 3000, "env": {"DATABASE_URL": "file:./dev.db"}}