How deploys work

Connect a repo once. After that, you deploy by pushing to your main branch.

This page covers the GitHub flow. You point Dockhold at a repo, and every push to your main branch ships a new version. Here is what happens from your push to your app being live. No repo? You can also deploy a local folder with one command.

The flow

  1. You push to the main branch of a connected repo.
  2. GitHub notifies Dockhold that a push happened.
  3. Dockhold builds your app. Common stacks (Next.js, Vite, Node, static sites, FastAPI) build automatically on every account. Any other stack builds automatically with compute added, or from a Dockerfile at your repo root, which always works.
  4. The new version goes live with a rolling update. The old version keeps serving until the new one is healthy, so there is no downtime. The exception is an app with app storage: it is stopped first and then started again, so it is unreachable for a few seconds.

Your app stays at the same URL across deploys: https://your-app.dockhold.app. You can watch each build happen live in your dashboard.

Your first deploy

  1. Push to GitHub. Put your app in a GitHub repository.
  2. Connect the repo. Open the dashboard and connect it. On a paid plan Dockhold auto-detects the stack (Node, Python, Go, Rust, Ruby, Deno, Bun, Java, PHP) and builds it. On a free account, add a Dockerfile at the repo root and it builds from that.
  3. Go live. Your app comes up at its dockhold.app URL.

One rule matters above all: your app must listen on 0.0.0.0 and read its port from the PORT environment variable. Don't hardcode a port and don't bind to localhost, or traffic can't reach it. See the Quickstart for examples.

Auto-deploy on push

How auto-deploy gets set up depends on how you connected the repo:

  • Connected with the GitHub app: auto-deploy is on from the start. Every push to your main branch deploys. Nothing else to do.
  • Using a personal access token instead: turn on auto-deploy in your app's GitOps settings, then add the push webhook it shows you to your repo on GitHub (Settings, then Webhooks). Pick the application/json content type and the push event.

Either way, Dockhold verifies every push notification cryptographically before it builds, so no one can trigger a deploy to your app without your secret. You can rotate that secret anytime from GitOps settings. Update it on GitHub at the same time so the two stay in sync.

Build again

Every app page has a Build again button next to Restart. It builds the app again from the latest commit on your repository's default branch, or from your last upload with the CLI, and puts it live when the build passes. If the new build fails, the version that was live stays online. Use it after a failed build, or to ship new commits when auto-deploy is off. Your AI tool can do the same with the MCP rebuild_app tool.

Custom builds

Add a Dockerfile at the repo root and Dockhold uses it as-is. It never overrides your Dockerfile. To point at one in a subfolder, add a dockhold.json at the root:

{ "build": { "dockerfile": "path/to/Dockerfile" } }

No Dockerfile? Common stacks (Next.js, Vite, Node, static sites, FastAPI) build automatically on every account. Automatic builds for any other stack are included once you add compute. New to this? Dockerfiles and dockhold.json explains what these files are and has copy-paste templates for Node, Python and Go.

PHP apps

A repo with composer.json or index.php at the root builds automatically once you add compute. On a free account, add a Dockerfile.

  • Version. Dockhold picks the newest PHP your require.php in composer.json allows, from 8.2, 8.3, 8.4 and 8.5, always on a release with the latest security fixes. "php": "^8.3" builds 8.5, "php": "~8.3.0" stays on 8.3, and no require.php builds 8.5. Every rebuild picks up the newest patch release of that version.
  • Older PHP. If require.php allows only PHP versions that no longer get security fixes, the build stops and tells you what to change: raise it, for example to ^8.4, or add your own Dockerfile.
  • What the build runs. composer install --no-dev with an optimized autoloader, after npm run build when package.json has a build script (Laravel with Vite). When public/index.php exists, public/ is the web root; otherwise the project root is, with dotfiles, vendor/ and composer.json kept private. A request that matches no file goes to index.php. .htaccess files are not read.
  • Extensions. The standard set plus pdo_pgsql, pdo_mysql, bcmath and OPcache. Need another? Add a Dockerfile that starts from the official PHP image.
  • Laravel. Add APP_KEY (run php artisan key:generate --show on your machine) and APP_URL=$(DOCKHOLD_APP_URL) as variables. Logs go to your app's logs, sessions to a signed cookie and the cache to local files, until you set LOG_CHANNEL, SESSION_DRIVER or CACHE_STORE yourself. For a Managed Postgres database, set DB_CONNECTION=pgsql and DB_URL=$(DATABASE_URL).

Next: write your first Dockerfile, connect a private repo, or set up environment variables and secrets.

Suggested guides
↑↓ to move ↵ to open Esc to close From the Dockhold docs