Building apps

The deploy lifecycle

A deploy turns your code into a running app behind a URL. There are two ways to start one — push to a connected GitHub repo, or upload straight from your laptop — and from there every deploy goes through the same steps. This page covers both paths and what happens in between.

Two ways to deploy

Both end the same way: a built, running, health-checked app. They differ only in where the code comes from.

PathHow it startsBest for
GitHub You connect a repo; a webhook auto-deploys on every push to source.branch. The day-to-day flow once an app is set up.
Local upload astrodock deploy --local uploads your working directory. No GitHub. Trying things out, no-repo apps, or deploying private code from your machine.

You can use both

An app can have a connected repo and still take a one-off --local deploy whenever you want. The manual path always works.

Path A — Connect a GitHub repo

Once a repo is connected, you stop thinking about deploys: every git push to the configured branch ships automatically.

What you need first

Connecting a repo requires the platform to have a GitHub token so it can read the repo and create a webhook. That's set once, on the platform, as ASTRODOCK_GITHUB_PAT (in the platform's .env / dashboard) — it is not an app variable and never goes in app.json.

Connect it

Name the repo in app.json under source, then run apply:

"source": {
  "githubRepo": "your-org/invoice-tool",
  "branch": "main"
}
astrodock apply

On apply, Astrodock connects the repo and creates a webhook on it. From then on, a push to main (or whatever source.branch is) triggers a deploy on its own. You can also set the repo from the dashboard instead of in the manifest.

Monorepos

If the app lives in a subdirectory, set source.repoPath (e.g. "apps/web"). The deploy builds from there instead of the repo root.

Path B — Deploy from your laptop

No repo, no webhook — just upload what's in the current folder:

astrodock deploy --local

The --local flag packages your working directory and uploads it, then runs the exact same build/run/health steps as a GitHub deploy. This is what Deploy your first app uses, and it's the quickest way to iterate before (or instead of) wiring up GitHub.

What a deploy actually does

However it's triggered, every deploy walks the same pipeline. Each step streams into a log you can watch live:

  1. Get the source

    Clone or pull the connected repo at source.branch, or unpack the upload from a --local deploy. If repoPath is set, that subdirectory becomes the deploy root.

  2. Check the required-variable gate

    Before any building happens, the platform confirms every required value is set. If anything is missing, the deploy stops right here — nothing is cloned, built, or run. (Details below.)

  3. Build

    For a Node app: npm ci plus your buildCommand for the frontend, and npm install for the server. For a Docker app: docker build from your Dockerfile.

  4. Run

    Start the app — a Node process for the buildpack, or a container for a Dockerfile app — with all the injected environment variables in place.

  5. Health probe

    The platform hits your GET /health. A 200 marks the deploy healthy; otherwise it's recorded as failed.

  6. Record & log

    The deployment is recorded as success or failed, with the full streamed log kept so you can read it after the fact.

Watching a deploy

From the CLI, add :watch to stream the log to your terminal until the deploy finishes:

astrodock deploy:watch            # GitHub-connected app
astrodock deploy:watch --local    # upload + watch in one go
Uploading 12 KB for "starter"…
Local deploy triggered for "starter" (deployment …)
[…] Installing server deps…
[…] Building frontend (npm run build)…
[…] Health probe: app is responding
[…] Deploy complete

✓ deploy success

You can also watch from the dashboard: the Deploys tab lists every deployment and its status, and the Logs tab shows the streamed output. After a deploy, your app's runtime logs are also available with:

astrodock logs --lines 200

The required-variable gate

A deploy is blocked until every value the app needs is set. The gate runs before any clone or build, so a misconfigured app fails fast and clearly instead of half-deploying. It checks two things:

If anything is missing, the deploy is rejected with a list of exactly what to set. Set the values and try again:

# the CLI reads the value from stdin so it never lands in your shell history
astrodock set-secret OPENAI_API_KEY
astrodock set-secret ASTRODOCK_DATABASE_URL

Why a gate at all?

It guarantees an app never starts up missing a database URL or an API key it declared it needs — you get a clear error before the deploy, not a crash loop after it.

Redeploying & triggering manually

For a GitHub-connected app, the normal way to redeploy is to push to the watched branch. To kick off a deploy by hand at any time:

astrodock deploy             # deploy the app configured in this folder
astrodock deploy my-slug     # deploy a specific app by slug
astrodock deploy --local     # upload the working dir and deploy that

You can also trigger a deploy from the dashboard's Deploys tab. Each run is its own recorded deployment, so you can always see what shipped and when.

Next steps

Related