Deploy

GitHub Deployment

Use a GitHub repository as the project source when you want to publish the application from source code and the build flow configured during creation.

This page describes the GitHub integration and its specific features. To configure another Git provider, see Deploy from Forgejo.

Required permissions

ActionMinimum scope
Create an HTTP projectproject.create on organization:*
List GitHub repositories and branches when creating the projectproject.source.update on project:*
Configure the repository, update mode, or GitHub commandsproject.source.update on project:<project-id>
Trigger a manual deploymentproject.deploy.trigger on project:<project-id>
Read builds and logsproject.logs.read on project:<project-id>

owner has full access. assistant, member, and organization API Keys need the corresponding grants.

Prerequisites

Before selecting a repository, complete these two required steps:

Note: The GitHub App can be installed on a personal account or an organization. In organizations, installation may require administrator approval.

Steps

  1. In the console, click Create project and choose HTTP Application.
  2. In Advanced Settings, set Project Source to Git repository and Git provider to GitHub.
  3. Select the repository, branch, runtime, and project commands. If the application lives in a subfolder of the repository, fill in Root directory; see Root directory and monorepos.
  4. Choose one of the four project update modes.
  5. Click Create Project.

The first build starts during project creation and uses the selected branch. After that, the selected update mode determines which events start new publications.

GitHub update modes

Each project uses one update mode at a time. Manual publishing remains available in every mode.

ModeWhat starts an update
ManualA manual action in the Console or a call to POST /v1/project/:id/github/deploy. Repository changes do not start updates.
Automatic by branchA push to the selected branch.
By TagCreation of a tag that matches the configured pattern. Updating or removing an existing tag does not start a publication.
By ReleasePublication of a non-draft release whose tag matches the pattern. Prereleases are disabled by default and can be included in the settings.

In the Console, Automatic by branch is selected initially when creating a GitHub project. You can choose another mode before creating the project or change the setting later.

In By Tag and By Release modes, the pattern matches the full tag name, is case-sensitive, and accepts 1 to 255 characters. The only wildcards are *, which matches any sequence of characters, and ?, which matches one character. The pattern v* matches tags such as v1.2.0; glob syntax with classes or alternatives, such as v[12].*, is not accepted. The * pattern matches any tag name.

Change the update mode

You can change the update mode after creating the project. In the Console, open the project, find the GitHub deployment card, and choose Edit settings. You can also update it through the API; see GitHub Builds for the endpoint. Changing the mode does not change the repository or branch selected for the project.

In projects that show the Git repository section on the project page, the update mode is part of the repository form. Choose Select or change repository, select the repository, and pick the Deployment mode; for By Tag or By Release, fill in the Tag pattern. Then click Save repository. Saving does not start a build: the next publication comes from the configured event or from a New build. Saving only a different branch of the same repository keeps the By Tag or By Release mode already configured.

New build in By Tag and By Release modes

In By Tag and By Release modes, New build in Build Logs does not use the branch: it publishes the latest version that matches the configured pattern.

  • By Release: the most recently published non-draft release whose tag matches the pattern. Prereleases are included only when enabled.
  • By Tag: the most recent tag, by commit date, that matches the pattern.

In these modes, the branch and commit SHA fields are not shown. If no published version matches the pattern, the Console shows "No published version matches the pattern" and no build is created; publish a release or tag and try again. Through the API, a request with branch or commit_sha in these modes is rejected.

Project commands

In GitHub projects, Zenifra installs dependencies according to the selected runtime, runs pre-build and build during the build, and uses start when the application starts:

  • pre-build is optional
  • build is optional
  • start is required

This is the order of the steps. Some projects only need start, while others also use pre-build and build. Every step runs inside the project's Root directory.

The project's environment variables are available in pre-build and build, so values such as VITE_* and NEXT_PUBLIC_* can be built into the application code. After changing a variable used in the build, start a New build; see Variables during the build.

Root directory and monorepos

The Root directory field sets the repository folder where dependency installation, pre-build, build, and start run. The default is ., the repository root.

In a monorepo, enter the path of the application folder from the repository root, for example backend or apps/api. Only the contents of that folder go into the build: files such as package.json, package-lock.json, and requirements.txt must be inside it.

  • use a relative path inside the repository, with / as the separator
  • absolute paths (such as /app) and .. are not accepted
  • a leading ./ and a trailing / are ignored: ./backend/ is the same as backend
  • if the folder does not exist on the published branch, the build fails with the message "The configured root directory does not exist in the repository."
  • Root directory cannot point to .git: that folder is not part of the build and is reported as a folder that does not exist. The .git folder is not included in the published application either; if the application needs the current commit, use an environment variable

You set the Root directory when you create the project and can change it later on the edit project screen, next to the commands. Just like changing the commands, saving a new root directory starts a new build.

To publish two applications from the same repository, such as an API and a frontend, create one project per folder, each with its own Root directory.

Node.js dependencies

With the Node.js runtime, dependency installation runs npm ci before any pre-build or build command. For this flow to work:

  • keep package.json and a valid package-lock.json together in the folder set in Root directory (the repository root by default), on the selected branch
  • generate and commit package-lock.json whenever dependencies change
  • verify the project locally with the same Node.js version selected for the project
npm ci
npm run build # only when the project has a build script
npm start

The package-lock.json must be synchronized with package.json. To use the commands in these examples, define the start script in package.json. Set the build field to npm run build only when the build script exists; otherwise, leave the field empty.

By default, npm ci installs the dependencies declared in the lockfile. Keep TypeScript, bundlers, and other tools required by the build command in devDependencies. If the project configuration sets NODE_ENV=production for the build, that install omits those dependencies; in that case, set pre-build to npm install --include=dev. That command runs after npm ci and before npm run build, making the tools available to the build. The current runtime does not prune devDependencies after that step. It cannot replace the initial installation with pnpm or Yarn. Projects and workspaces that depend on those package managers must provide a compatible npm package-lock.json. Zenifra does not automatically convert a pnpm- or Yarn-specific workspace; when that lockfile cannot be maintained, publish an OCI Image built outside this flow.

Build time and cache

The first build of a project installs every dependency and runs every command. Later builds reuse the steps whose files and settings did not change:

  • dependency installation runs again only when package.json, package-lock.json (or the runtime's dependency files) change
  • pre-build and build run again when the code in the Root directory changes
  • changing an environment variable runs every step again on the next build, because variables are available to pre-build and build
  • a new build of the same commit, with the same variables, finishes in a few seconds

The cache belongs to each project and is not shared between projects. Zenifra does not store variable values in the published application or in the cache; only the values your build writes into files, such as VITE_* and NEXT_PUBLIC_*, are part of the result.

When a push changes only code, the installed dependencies are reused as they are: they are neither installed nor published again, which makes the build and the update faster.

Git history during the build

The build only receives the files of the published commit, without the repository history and without the git command. Build scripts that read the history, for example git log to compute page modification dates for a sitemap or git describe to generate a version, fail at this step.

Generate that information before committing and version the result in the repository, for example with a workflow that updates a JSON file on every push to the main branch. To identify the published version at runtime, use the ZENIFRA_INSTANCE_VERSION variable.

Build troubleshooting

Use Build logs to identify the failed step and follow the matching guidance:

ErrorHow to fix it
Missing or unusable package-lock.jsonGenerate a valid npm lockfile, commit it next to package.json on the selected branch and root directory, then create a new build
package-lock.json is out of syncRun npm install to update the lockfile, commit the changes, verify with npm ci, and create a new build
GitHub repository access rejectedZenifra automatically attempts to renew the binding to the same repository. If the console still says authorization is required, use Reconnect repository in the project and start a new build
The configured root directory does not exist in the repository.Check the Root directory on the edit project screen: the folder must exist on the selected branch, with the path from the repository root. Fix the value and save to start a new build
Commit unavailableCreate a new build from the current state of the selected branch. If the error continues for current commits, contact support
spawnSync git ENOENT or git: not foundA build script is reading the Git history, which is not part of the build. See Git history during the build
VITE_* or NEXT_PUBLIC_* value missing or outdated in the applicationCheck the variable in Edit project and choose New build in Build logs: saving the variable restarts the instances but does not rebuild the application
Unclassified causeReview the output of the failed command in the Build logs and the project commands

Automatic updates by branch

In Automatic by branch mode, each push to the selected branch triggers a new update. The first build already started during creation; this mode controls later push-triggered updates.

In Manual, By Tag, and By Release modes, a branch push does not start an automatic update.

Preview Environments

Use Preview Environments to give each pull request a temporary URL without replacing the primary project. For GitHub-sourced projects, the native path creates and updates previews without a workflow, API Key, or image in the repository. In the project's Preview Environments section, choose Configure previews, turn on Enable Preview Environments and Enable automatic GitHub previews, and choose the Preview target branch. This choice is independent from the primary update mode.

For pull requests in the project's own repository, opened, reopened, and synchronize create or update the pr-<number> preview when the target is the selected branch; edited reevaluates target branch changes and closed removes the preview. Pull requests targeting another branch and pull requests from forks do not participate in the native flow. Pull requests opened before activation are not imported until a later relevant event. The preview uses the runtime and commands already configured for the project while keeping the primary application's version separate.

Automatic previews depend on the pull request permission of the Zenifra GitHub App. If the installation has not approved that permission yet, no preview is created; see GitHub App permission.

If an Action already manages pr-<number> for the same project and pull request, the native flow neither adopts nor overwrites that preview: the native run is blocked. Choose one flow for that key.

Projects whose source is an OCI image do not use the native flow: their previews are created by the GitHub Action with a ready-to-use image. See the recommended pull request workflow.

What stays fixed after creation

In GitHub-based projects, these fields are defined during creation and are not available for editing later:

  • project source
  • branch
  • runtime
  • runtime version

After creation, you can also change the update mode. The pre-build, build, and start commands and the Root directory remain editable.

Build Logs

After the project is created, follow each publication from the Build logs section of the project page in the console.

This history shows:

  • recent builds
  • current build status
  • each project command, in the order it runs, as $ command followed by its output: dependency installation (for example $ npm ci), pre-build and build, when present
  • progress messages, such as the commit used, the build start and the publication

When a step has not changed since the previous build, it is reused: the command still appears in the log (for example $ npm ci or $ npm run build), followed by a line saying it was reused. When a command fails, its output appears in the log, followed by a final message with the identified cause.

Logs show only the output of the project's commands and progress messages; internal platform details never appear.

The log modal updates in real time while the build is running.

Superseded builds

Only the latest build of a project is published. When a new build starts (from a push, a tag, a release, or a New build), earlier builds of the same project that have not finished show as Superseded:

  • if they were still queued, they never run, and the new build starts sooner;
  • if they were already running, they finish, but the result is not published.

A superseded build is not a failure and does not change the running application.

Retention

Build history is retained for up to:

  • 30 builds per project
  • 30 days of age

Whichever limit is reached first removes the oldest records.

URL

Each public project receives a URL in *.clients.zenifra.com. Always use the URL returned by project creation or project lookup as the source of truth. From the Premium plan up, the subdomain name can be customized.

Next steps

Last updated on

On this page