Deploying from GitHub
Apps/Ship/Deploying from GitHub

Deploying from GitHub

An environment can follow a branch on GitHub. A push to the branch syncs the environment's files, and production deploys from it, with no CI workflow or API key.

Connecting a repository

Open Settings → Git on the app. The repositories listed are the ones the team's Inference Bureau GitHub App installation can read: the same App Auditor uses, so a repository it already reviews is there too. Install on GitHub installs it, or adds a repository to an installation, and GitHub brings you back.

For each environment, choose Follow a branch and pick:

FieldWhat it is
RepositoryOne the installation can read.
BranchThe branch whose pushes the environment takes, such as main or staging. Each environment follows at most one branch; several can follow the same one.
FolderOptional. In a monorepo, the folder holding the app (where its package.json and settings.ib.ts are), such as apps/portal. Paths are read from there.
ThroughProduction only: the development environment a push lands in first. See Production.

Following starts with a sync of the branch as it is now, within a minute. Owners and admins set this up, as they deploy.

What a push does

The commit's files are read from GitHub, hashed and compared with the environment's, as ib-apps push does with a folder:

  • What differs is pushed; files the commit no longer has are deleted. Each batch of up to 200 changes is a file version, and Logs shows it as a push with the commit.
  • .ibignore at the app's folder applies, and .git, node_modules, .next and the other never-synced folders stay out. Paths left out are neither sent nor deleted. The generated web/ib-client.d.ts is kept when the repository has none.
  • Files over 1 MiB go to the team's file store, up to 50 MiB each, as large files from the CLI do.
  • The dev server takes the change and reloads, and Shopify extensions release, as after a CLI push.

A newer push queued before an older one runs replaces it. A commit with a file the environment can't take (too big, or a path it refuses) still applies the rest, and the sync is marked failed with the files named.

LimitValue
Repository archive80 MB
Files in an environment2,000
One file50 MiB

Production

Production follows a branch through a development environment that follows the same branch: the push lands there first, then production deploys from it, exactly as a deploy does. The deploy plan's schema rules, the build, the Shopify release and rollback all work the same, and Settings → Deploys shows each deploy's commit. A development environment that follows nothing yet starts following the branch with production.

To review before production, have development follow a working branch and production follow main through another environment, such as staging: a merge to main ships.

Deploy again on production's card takes the branch's head again and builds production even when no file changed, which is how it picks up a changed environment variable. Sync now does the same for a development environment.

While production follows a branch, Deploy in the dashboard and ib-apps deploy are refused: production changes only by a push. Roll back still works.

A followed environment

The branch is the environment's one source of truth. The dashboard's file editor shows it read-only, and the assistant and ib-apps push or ib-apps dev are refused with the branch named. Records, actions, variables and the dev server work as before; only files are git-managed.

On GitHub

Each sync is a GitHub Deployment on the commit, to an environment named after the app and environment, such as portal (production). It's in progress while the files apply and production builds, then successful with the environment's address, or failed with a link to its Logs. A failed production build also emails the team, as any deploy does.

The deploy-plan check

A pull request into a branch an environment follows gets a check on its head commit, Deploy plan · <app>, saying what deploying that commit would do to production as it runs now: the files it adds, changes and removes, each model change, and how many of production's records each one reaches. It runs again on each push to the pull request.

A change reaches production's records when a removed field or model still holds values (they're hidden, and kept for a rollback), a new type can't read some stored values, or a new required or unique rule is already broken by existing records. Those, and a schema that can't be read, fail the check, so they show before the merge instead of at deploy. Set it to only warn under Pull requests on Settings → Git, or turn the check off there.

Type errors aren't in the check: a preview's Problems panel shows them, and the production build type-checks pages.

Preview environments

With Preview environments on, opening a pull request into a followed branch creates pr-<number>, a development environment following the pull request's branch. Each push to the branch syncs it like any followed environment, its address shows on the pull request as a GitHub Deployment, and merging or closing the pull request deletes it with its records and files.

SettingWhat it does
RecordsStart empty, or as a copy of production's records when the pull request opens, with email, password, encrypted and name-like fields anonymized (up to 50,000 records).
At onceHow many previews can be open, 1 to 5. Each is one of the app's development environments. Past it, the pull request's check says there's no preview until one closes.

A preview's variables are development's, and its dev server sleeps when idle, as others do. Pull requests from forks don't get one, since their code would run with the app's variables. Previews are for web apps; a Shopify app's would need its own dev store install. Delete in the Previews table removes one early, and the pull request's next push makes it again.

Deploying from your own CI

Teams that keep their own CI can push and deploy with a deploy token instead of following a branch. Create one under Deploy from your own CI on Settings → Git. It reaches one development environment: Push lets it change that environment's files, and Push and deploy also deploys production from it. It never reaches records, settings or other environments. It's shown once; add it to the repository's secrets.

In a folder that isn't linked, such as a fresh checkout, ib-apps push --app <slug> --env <environment> sends what the folder has, deleting what's only on the server, as a sync from GitHub does. Then ib-apps deploy ships it. With the token as IB_API_KEY:

on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npx -y @inferencebureau/apps@latest push --app portal --env staging
        env:
          IB_API_KEY: ${{ secrets.IB_DEPLOY_TOKEN }}
      - run: npx -y @inferencebureau/apps@latest deploy --app portal --env staging
        env:
          IB_API_KEY: ${{ secrets.IB_DEPLOY_TOKEN }}

An environment that follows a branch refuses a token's pushes as it does the CLI's. Revoking a token turns CI away at its next call.

Stopping

Stop following, in the ⋯ menu of an environment's card on Settings → Git, leaves the environment's files as they are and lets the editor, the assistant and the CLI write to it again. A deleted branch, or a repository removed from the installation, stops the following the same way. It never empties the environment.