# Deploy a GitHub project on blitz.cloud

> Connect GitHub or paste a link to a public repository, and blitz.cloud builds the code and puts it online with HTTPS, with a new version on every push. How the build works, which port is used and what fails.

Web page: https://blitz.cloud/docs/deploy-from-github/
Updated: 2026-10-19

Connect your GitHub account and blitz.cloud builds your projects, private ones included, and puts a new version online every time you push. You can also skip connecting and paste a link to any public GitHub repository. It does not have to be your repository. We clone it, build it and run the result under your address with HTTPS. If the project has a Dockerfile we use it; if it does not, we write one from what is in the repo, and rewrite it if the build fails.

## Connect GitHub

Click "Connect GitHub" during onboarding or on the Settings page. GitHub then asks which repositories blitz.cloud may read: all of them, or only the ones you pick. You can change that choice on GitHub at any time.

Once it is connected:

- "My own code" lists your projects with a search field. Private ones are marked Private. A project that is missing is one blitz.cloud may not read yet, and "Choose which projects on GitHub" takes you to the list at GitHub.
- Every push to the app's branch is built and put online by itself.

With or without a connection, you pick the branch from a list, in the wizard under "Advanced settings" and later on the app's Settings tab.

## Step by step

1. Open [dashboard.blitz.cloud](https://dashboard.blitz.cloud/) and click "Host something new".
2. Choose "My own code".
3. Pick one of your projects, or paste a link, for example `github.com/docker/welcome-to-docker`, and click Continue.
4. Give the app a short name. That becomes the subdomain: `demo` turns into `demo.<you>.blitz.cloud`.
5. Click "Build it and put it online" and watch it happen.

The first build takes a few minutes, because everything the project needs is downloaded from scratch. Later builds of the same project reuse the layers that did not change.

While it builds, the app's Overview shows each step as it happens, and your place in the queue if builds are waiting. Builds run on their own build servers. The free plan builds one project at a time, Pro builds three at once and goes ahead of the queue.

## How the build works

| Your project has | What we do |
|---|---|
| A `Dockerfile` in the root, or in `docker/` | We build it |
| Other Dockerfiles, such as `bot.Dockerfile` or `api/Dockerfile` | We look through the whole project and pick the one that is the app, or build the one you pick under "Advanced settings" |
| No Dockerfile | We write one. A language model reads the file listing and the manifests (package.json, requirements.txt, go.mod and the like), writes a Dockerfile, and the build is what decides whether it was right |

Both run in a sandbox with no access to anything of ours or anyone else's. A build can reach the internet to download dependencies, and nothing on the private network.

A build gets the size the project needs: small (1 core, 2 GB, up to 4 cores), medium (2 cores, 5 GB, up to 6 cores) or large (4 cores, 10 GB, up to 7 cores). The memory of each size is fixed; the cores can grow when the build server has some to spare. The first build is sized by what kind of project it is. After that, every build measures how much memory it used, and the next one is sized from that. The build log says which size it got and why.

When a written Dockerfile does not build, the model reads the end of the log and rewrites it, up to three times. The Dockerfile we wrote is shown under the log of every such build. Copy it into your project as `Dockerfile` if you want the build to be the same every time, and we use yours from then on.

A recipe that worked is kept. The next commit builds with it, and we only write a new one when that build fails. The recipe is also remembered against that exact code, by commit and by content. If somebody else deploys the same public project at the same commit, or the same content under another name, their build starts from what we already worked out and nobody asks a model again. Plans from private repositories are never shared.

Content of your repository is treated as data when we write a Dockerfile: a README that tries to give the model instructions is a README. The recipe is checked before it is built, and the build runs in the same sandbox as everything else.

## When a build fails

When a build or the first start fails and our own retries are used up, the app page says what went wrong in one sentence and lists the steps that fix it, each with its own button. Paste a key (with a note on where to find it), set up a database, use another Dockerfile, or let us write one. What blitz.cloud can do safely, it does by itself and ticks off. It never makes up a key or an address that belongs to somebody else.

Some problems are named exactly. When the code asks for `9O6A5180.jpg` and the repository has `9O6A5180.JPG`, the page says so, with the file and the line that asks. Windows and macOS ignore capital letters in file names, our servers do not.

The full build log is on the app's Overview while it builds, and on the Activity tab afterwards.

## Which port your app listens on

We tell your app to listen on `8080` through the `PORT` environment variable, which is what a Dockerfile we write uses. If your Dockerfile declares a different port with `EXPOSE`, we read that from the image after the first build and use it instead.

Your app runs as the user your Dockerfile names. Without a `USER` line that is root, inside the app's own gVisor sandbox, so an image that expects root works as it would on your machine.

## When your code changes

With GitHub connected, every push to the app's branch builds a new version and puts it online. Without it, click "Get the newest code" on the app's Settings tab. It builds whatever is newest on the branch and puts it online. Either way, the version currently running stays up until the new one works, so a build that fails changes nothing. If you push again while a version is being built, that build stops and the newest code is built instead. The version that is online keeps running until the new one is ready. If the new version builds but does not start within ten minutes, we put the version before back and say so on the Activity tab. Any of the last 10 versions that went live can be put back from there with "Put this version back".

Pushes that come in quickly are built together as one build of the newest commit. On the free plan a push waits until 3 minutes go by without another one, and an app is built from pushes at most every 15 minutes. On Pro, at most every five minutes. A push whose commits all come from a bot or a GitHub workflow builds nothing, and neither does a commit whose message says [skip ci] or [skip blitz]. If one of your workflows is meant to put new versions online, switch on "Build pushes made by bots and workflows" on the app's Settings tab. An app that gets more than 12 pushes in an hour is built from pushes at most every 30 minutes until an hour goes by with fewer. "Get the newest code" always builds at once.

With automatic updates switched on (the default), we also look every night around 4:00 UTC whether the branch has moved, and build and put the newest commit online if it has. On the free plan we skip this while nobody has signed in to the account for 7 days, and for an app with an address that nobody has visited for 14 days.

## Build on your own GitHub Actions

Builds normally run on blitz.cloud's build servers, one at a time per account on the free plan. You can also let GitHub build the app with your own Actions minutes: switch on "Build on your own GitHub Actions" on the app's Settings tab, or tick "Also build my new apps on my own GitHub Actions" when you connect GitHub. The same switch shows up under a build that is waiting for a build server.

Switching it on adds one file to the repository, `.github/workflows/blitz-cloud.yml`, in a commit by blitz-cloud-app on the branch the app follows. If we wrote the project's Dockerfile, we add that too once it has put the app online, so you can read and change it with the rest of your code. When the app needs a new version, blitz.cloud starts the workflow. It asks GitHub for a signed token, gets the build from us with a credential for this app's images only, builds the image on GitHub's machine and stores it on blitz.cloud. From there it goes online exactly like a build of ours, with the same checks and the same way back if it does not start. The build log is on the app's Overview, with a link to the run on GitHub.

Builds on GitHub Actions don't count toward your blitz.cloud build minutes. Public repositories build on GitHub Actions for free; a private one uses your GitHub minutes, and GitHub's free plan includes 2,000 a month. If GitHub does not start the build within ten minutes, we build it on our own servers instead and say why in the log.

This needs our GitHub App to be allowed to write to the repository and to start workflows. An older connection may only allow reading. Then GitHub asks the owner to accept the new permissions first, and the switch links to that page. To go back, switch it off. The workflow file stays in your repository and does nothing until blitz.cloud starts it, so delete it whenever you like.

## Private repositories

Connect GitHub and allow blitz.cloud to read the repository there. It then shows up under "My own code", marked Private, and builds like any other project. We only see the repositories you allowed.

To write or repair a Dockerfile, the language model reads parts of the project, and for a private repository that means parts of code you have not published. What it reads is listed on [Data and GDPR](https://blitz.cloud/eu-data/).

## A public address that isn't GitHub

Paste any public `https://` git address instead of connecting an account: GitLab, Codeberg, a self-hosted Gitea or git server, anything that answers plain git-over-HTTPS. Pick "My own code" and paste the address where you would paste a GitHub link.

This works like a public GitHub link, but with two limits. The project needs a `Dockerfile` in its root. We don't write one for it and we don't look in subfolders. There is also no connected account, so nothing builds automatically when the code changes. Click "Build again" on the app's page, and we read the branch you picked again from the same address and build its newest commit.

## Environment variables and databases

Set environment variables on the app's Environment tab after the first deploy. They are encrypted before they are stored and applied on the next restart. See [settings and files](https://blitz.cloud/docs/settings-and-files/).

A managed database is created from the Databases page and connected to the app there. When a build begins, we also look in the project for a database driver and the setting the code reads its address from. If the project cannot start without a database, we set one up, connect it before the app starts and say so in the build log. That happens once per app, never over a setting you made and never past your plan. See [databases](https://blitz.cloud/docs/databases/).

## Common problems

- **"This project has no Dockerfile, and we could not write one for it right now"**: the model was unavailable or the account's AI allowance for the day is used up. Adding a Dockerfile to the repository is the reliable fix, and works without any model.
- **"We couldn't build this project" followed by a reason**: the written Dockerfile was rewritten up to three times and still failed, and the sentence says what the model saw. The full log is underneath.
- **The build fails while installing dependencies**: the log below the failure has what the installer said. A lockfile that does not match the manifest is the usual cause.
- **The build ran out of memory**: it is built again once with the next bigger builder. On the free plan a build gets at most a medium builder (5 GB); one that still runs out says so, and Pro and Business builds get up to 10 GB. A large build that still runs out says it needs more memory than a build can have. Get in touch and we will look at it.
- **The app is "Starting" and never answers**: it is listening somewhere other than the port we are sending traffic to. Make it read `PORT`, or add `EXPOSE` to the Dockerfile and deploy again.
- **"Part of this project is built for a different kind of processor"**: our servers are x86. A base image that only exists for arm64 will not run.

## Several services in one repository

A web front end, an API and a worker that share one repository go online as one app with one address. If the project has a compose file, the wizard reads it and proposes the parts it found: the front end at `/`, the API on its own path such as `/api`, the worker in the background. Databases and development tools in the compose file are left out, each with a reason. You can still put only one of the services online instead.

- Parts find each other by name. A setting like `BACKEND_SERVICE` is filled in with that part's address inside your account, the way it worked in compose.
- A part can have a Dockerfile of its own. All parts are built in one build, update together and go back together.
- A step can run before each new version, like a database migration. If it fails, the version you had keeps running and the Activity tab shows what the step printed.
- Each part that keeps running counts as one of your plan's apps. The step before each new version does not, and neither does a part you switched off.
- Only the parts people visit go to sleep. A bot keeps running while its dashboard sleeps.

The app's Settings tab has a Parts section for start commands, paths and switching a part off. The Logs tab switches between parts.

For an app of one part, you choose two things under "Advanced settings" in the wizard, and later on the app's Settings tab:

- **Dockerfile**: any Dockerfile we find on the branch (`Dockerfile`, `Dockerfile.bot`, `api.Dockerfile`, `Containerfile`, in any folder), or "Write one for me" to have us write one even though the project has its own. Every app can use a different one.
- **Start command**: replaces the image's `CMD` and keeps its `ENTRYPOINT`, the same as `docker run image <command>`. With `ENTRYPOINT ["/bin/sh", "/app/entrypoint.sh"]`, a start command of `bot` runs `/bin/sh /app/entrypoint.sh bot`. For more than one step, write `sh -c "npm run migrate && npm start"`. The settings show what the Dockerfile starts with and what your command turns it into.

A different Dockerfile builds the app again, and the running version stays online until the new one works. A different start command restarts the app.

You often don't have to type the start command. If the project's ENTRYPOINT is a script with a `case "$1" in` that lists what it accepts, or you put only one service of a compose file online, the wizard shows the services and asks which one the app is. If an app stops because nobody chose, its page offers the services as buttons. When the project doesn't say, and the first start stops without a start command, our assistant reads the project and what the app printed, and either starts it with the one service it found or offers the ones it found.

## Bots and background workers

A Discord bot, a queue consumer or a scheduler connects out and is never visited. Switch on "Runs in the background" when you name the app. It then gets no address and no port, we do not wait for it to answer on one, and it never goes to sleep. On the free plan it stops when nothing has happened in your account for 2 days: no sign-in, no deploy and no visit to the dashboard. We email you one day before. Press Start on the app's page and it runs again without a new build, for another 2 days. It counts as running once it has stayed up for 20 seconds, and if it keeps crashing the app page shows the last lines it printed, the same as for any other app. Its output is on the Logs tab.

An app that is already online can be switched on its Settings tab with "Run it in the background", which frees its address. A background app gets an address back with "Give it one".

## Monorepos

To build one folder of a repository, such as `apps/web`, name it under "Folder to build" in the wizard's advanced settings, or later under Settings > Where new versions come from. We build that folder as if it were the whole project. The wizard suggests folders that look like a project. Without a folder, the build starts from the top folder of the repository.
