docs/user/deploy/github.md
title: Deploy from GitHub description: Connect a repository, deploy on every push, wait for CI, and deploy only what changed.
Connect a GitHub repository to a service and Ployz builds and deploys it each time you push to its Git branch. How builds work covers what happens in between.
Add a service from a repository
- Go to Projects, click New project and choose GitHub repository. (To add it to a project you already have, click Create on that project's canvas instead.) The first time, click Connect GitHub, pick the account or organization, choose the repositories Ployz may use, and install the Ployz GitHub App. GitHub sends you back to Organization → GitHub, which lists the account. It says "Repositories appear in a moment" until Ployz has listed them. If the app is already installed on that account, for another Ployz organization, click Use existing instead.
- Search for the repository, or paste its URL, and pick it.
- Before you deploy, set what your app needs to start:
- To make it public, open Settings → Networking and click
Generate Domain. Enter its port in Port
if your app doesn't listen on
PORT. - If it needs variables or a database to start, add them now.
- For one app of a monorepo, set its root directory under Source.
- To make it public, open Settings → Networking and click
Generate Domain. Enter its port in Port
if your app doesn't listen on
- Click Deploy in the bottom bar.

The service is named after the repository and follows its default Git branch. The GitHub App reads your code, pull requests and checks, and can't push code. The repository list groups repositories by GitHub account. To give Ployz more repositories later, choose Add from GitHub below the repository list. GitHub opens in a new window, and the new repositories appear in the list when you come back.
Deploy a public repository without the app
In the repository list, type owner/repo or paste the repository's URL, choose Deploy
owner/repo, then deploy.
Without the app, Ployz never hears about pushes: no deploy on push, no Wait for CI, and no builds on GitHub Actions. Install the app on the repository to get them. Until then, shipping a new commit is CLI-only for now, because the dashboard's Deploy needs a staged change:
| 1 | # Builds and deploys the newest commit on the service's Git branch |
| 2 | ployz deploy |
Auto-deploy and Wait for CI keep their values on such a service, so they work as soon as
the app is installed. Until then, the dashboard shows a line under Auto-deploy, and ployz get
and ployz set print the same note:
| 1 | $ ployz set web.waitForCi=true |
| 2 | Applied web.waitForCi in shop/production. |
| 3 | Pushes reach Ployz only once the GitHub App is installed on owner/repo. |
Choose the Git branch
- Open the service and go to Settings → Source.
- Next to Branch, click the pencil and pick a Git branch. For a public repository, type its name.
- Deploy the change.

Each environment has its own settings, so production can follow main while staging follows
develop. See Environments and branches.
Protected environments
In a Protected environment, only an owner or admin can connect a repository or change the branch. Merging into that branch still deploys: Ployz doesn't decide who can merge. Use GitHub branch protection on the branch to require reviews before a merge.
The Ployz · ready to merge check on a pull request into that branch adds a line like Merging deploys to production, a Protected Environment. The line is informational: it never changes whether the check passes.
Deploy on push
Auto-deploy is on for every new service. Each push to the service's Git branch deploys it, in every environment that follows that Git branch. Turn Auto-deploy off under Settings → Source to deploy only when you choose. It applies at once, with no deploy.
A push deploys like Deploy: it ships every change you saved in the environment, and staged changes you haven't saved stay behind. The services that follow its repository and Git branch, have Auto-deploy on and match their watch paths build the new commit. Every other service keeps the commit it last built, and one with nothing new to ship keeps running as it is.
A volume deletion you confirmed when you saved goes out with the push without asking again. If the data changed since, the push keeps it and your next deploy asks; see Confirm a deploy that deletes data.
Wait for CI
Turn on Wait for CI under Settings → Source to hold a push's deploy until its GitHub checks pass, from GitHub Actions or any other app that reports checks. It applies at once.
A held push shows in Runs and in ployz deployment ls as a deployment that reads Waiting
for CI, named by its commit rather than a number. It deploys as that same deployment once
every check passes, and takes the next deployment number then, so deployments stay numbered in
the order they ran, whichever branch passed CI first. Cancel it there to drop the push. Nothing
was frozen for it, so it can't be redeployed: push again instead.
- If a check fails, the deployment reads CI failed and the commit doesn't deploy. Re-run the check on GitHub and the commit deploys once it passes, or push a fix.
- A newer push replaces a commit that's still waiting, and so does a deploy you start yourself. A replaced commit leaves the list; one you cancelled stays, so you can see you dropped it.
- If no checks run for a commit, it waits until your next push. CI that reports commit statuses instead of checks counts as no checks.
Deploy only when certain files change
Watch paths limit auto-deploys to pushes that change files you list. Under Settings →
Source → Watch paths, type a pattern and click Add. Patterns work like .gitignore and
start at the root of the repository, whatever the service's root directory is. They apply at
once.
| Pattern | Matches |
|---|---|
apps/web/** | everything under apps/web |
*.md | Markdown files in any folder |
/README.md | only the README at the root |
!**/*.md | leaves out Markdown files an earlier pattern matched |
Without watch paths, any change deploys. A force push, the first push Ployz sees on a Git branch, or a push that changes 300 files or more deploys every service on the Git branch, whatever their watch paths.
Deploy a monorepo
Add one service per app from the same repository, and give each its own root directory and
watch paths before you deploy it. For a repository with apps/web and apps/worker:
| Service | Root directory | Watch paths |
|---|---|---|
web | /apps/web | apps/web/** |
worker | /apps/worker | apps/worker/** |
To set the root directory, open Settings → Source, click Root directory and enter the
folder, starting with /. The build sees nothing outside that folder, and a Dockerfile path is
relative to it.
If an app imports code from elsewhere in the repository, like a shared package in a pnpm or npm
workspace, leave the root directory at /. Set a
build command and
Start command for that app instead, such as
pnpm --filter web build, and add the shared folder to its watch paths.
Who owns the connection
A GitHub installation belongs to the organization it is connected to, not to the person who installed it. Everyone in the organization can pick its repositories, and it stays connected when that person leaves. Organization → GitHub lists each connected account with its repositories, who connected it, and when. Only an owner or admin can connect or disconnect one; members see the list.
One installation can be connected to more than one organization. To connect one you already installed, click Use existing in the repository picker or in Organization → GitHub of the other organization. Ployz connects only GitHub accounts you own: your own user account, or a GitHub organization where you are an owner. Collaborating on one of its repositories is not enough. When you own several new ones, Ployz asks which to connect.
To stop an organization from using an account, click Disconnect on its row, or run
ployz github ls and then ployz github disconnect <login>. Builds that organization has in
flight on GitHub through that account stop, and their deploys fail with "GitHub account
<login> was disconnected". Other organizations connected to the same installation keep it,
and the app stays installed on GitHub. To uninstall it, use Uninstall on GitHub after you
disconnect.
Suspending the app on GitHub hides its repositories from every organization until you unsuspend
it; the connections stay. Uninstalling the app on GitHub removes it from every organization at
once. Either way, builds in flight through it stop within seconds, and their deploys fail with
"GitHub account <login> was suspended" or "was disconnected".
Read a repository from the CLI
To see what's in a repository before you deploy it, list its files and read one. Both work on any repository the Ployz GitHub App can read, and on public repositories.
| 1 | # Every file on the default branch |
| 2 | ployz github tree acme/web |
| 3 | |
| 4 | # Only files under apps/web, on the dev branch |
| 5 | ployz github tree acme/web apps/web --ref dev |
| 6 | |
| 7 | # Only files whose path matches a glob |
| 8 | ployz github tree acme/web --match '**/Dockerfile' |
| 9 | |
| 10 | # The text of one file |
| 11 | ployz github cat acme/web apps/web/package.json |
--match matches the whole path from the top of the repository, so *.toml finds only files at
the top, and **/*.toml finds them in every folder. Quote the glob so your shell doesn't expand
it. A listing stops at 500 files. When it's cut short, name a folder or a narrower --match to
see the rest. A folder or file the repository doesn't have fails with No path and exit code 1.
github cat says No file for a missing file, also with exit code 1.
github cat prints text files up to 64 KiB. For a larger file or a binary one, it says so
instead of printing it. Pass --ref to read a branch, tag or commit other than the default.
Good to know
- Every deploy ships the newest commit. Clicking Deploy to apply a setting also picks up whatever is on the service's Git branch now.
- Changing a variable rebuilds your app. See How builds work.
- Only the service's Git branch deploys. Pull requests can get their own preview environments instead.
- Merging a pull request brings its preview's setting changes. Its code deploys like any push, and the changes its preview made land in production as one saved change, Merged #146, that deploys with the merge. The pull request's Ployz · ready to merge check lists those changes first. It's informational: green, or neutral when something needs a look, and never failing.
Next: give your app its variables.