Skip to guide
Help center

Preview each pull request

Turn on pull request previews for a project, so each pull request gets its own environment, deployed on each push and deleted once it closes.

What a preview is

With pull request previews, each pull request opened on GitHub gets its own environment, named pr-<number>, to try it before the merge. Tenkai copies it from an environment of the project, such as staging, on the same cluster:

  • Its applications built from the repository of the pull request deploy the last commit pushed to it.
  • Its applications deployed from a container image wait for the image your CI builds for the pull request. See Applications from an image.
  • Its databases start empty, with their own credentials. See Databases of previews.
  • Its environment variables are copied without their sensitive values. Set the ones it needs as preview variables.

When the pull request is closed or merged, Tenkai deletes the preview and everything in it.

Turn previews on

Owners and admins turn them on.

  1. Turn on Environments and Pull request previews, under Experimental in the team settings. See Try an experimental feature.
  2. Connect the GitHub account of the repository to your team, from the team settings. See Connect GitHub.
  3. Open the project, then its Previews tab.
  4. Choose Edit next to General, choose under Copy from the environment previews copy, then Save.
  5. Turn the switch on.

Previews deploy as you. If you leave the team, previews turn off.

Tenkai cannot copy an environment with a hosted bucket, or with a web application that keeps files. Choose another environment.

Turning previews off opens no new preview. The open ones stay until their pull request closes.

Hako and your agents can set previews up too: ask them to turn previews on, change the limits, set a preview variable or the setup commands. You approve each change in the Hako panel. An agent needs the Change configuration scope for previews and Change variables for preview variables, see Agent tokens.

Limits

Previews run on the cluster of your project, beside production. Three settings keep them small. Choose Edit next to General, change them, then choose Save.

  • Previews at once: a pull request over it gets no preview, and GitHub says why beside its commit. Close a pull request, then push to the other one: Tenkai opens its preview.
  • Size of each resource: every application and database of a preview runs at this size, whatever its size in the environment it copies. A database server that previews share keeps the size of the one it copies.
  • Delete after idle days: Tenkai deletes a preview whose pull request had no push for that many days. Push to the pull request to open it again.

Databases of previews

Previews share one database server for each PostgreSQL and MySQL of the environment they copy, of its name and size. Each preview gets its own database on it, named after its pull request, such as pr_12_…, with a user that opens only that database. Your application reads it from its usual variable, such as DATABASE_URL.

  • The first preview waits for that server to start, about a minute. The next ones open without waiting, as long as one preview remains.
  • The Previews tab lists the servers under Shared databases, with their state. Choose one to open its page. The topology of a preview shows the server each of its applications uses. The project lists no environment of these servers.
  • Previews share the CPU, memory and connections of the server: a heavy preview slows the others, without touching their data.
  • A migration that changes the whole server, such as CREATE ROLE or CREATE USER, may succeed in one preview and fail in the next.
  • The servers take no backups.

Other services, such as Valkey, run once in each preview, at the size of the previews.

When a preview closes, Tenkai deletes its databases. Once no preview remains, even with previews on, Tenkai deletes the servers: the next pull request creates them again and waits for them.

The servers run on the cluster of the environment previews copy. To copy an environment of another cluster, wait until every preview closed: Tenkai deletes the servers, and the next preview creates them on the new cluster.

Preview variables

Preview variables set the values a preview needs, such as the test key of Stripe, over the ones it copies. Owners and admins enter them once for the project:

  1. On the Previews tab, choose Add variable… next to Preview variables.
  2. Enter the key and the value. Choose Sensitive for a secret: Tenkai never shows it again.
  3. Choose Save. A variable with the same key replaces the old one.

To remove a variable, choose Delete on its row.

Each preview created after the change gets them before its first deployment. The open previews keep their variables: change them in the preview itself.

Setup commands

Setup commands prepare a new preview once, such as a seed or the creation of a test account. They run in a web application of the preview, with its variables, after its pre-deploy commands and before it starts. Later pushes to the pull request run the pre-deploy commands only.

  1. On the Previews tab, choose Edit next to Setup.
  2. Under Run in, choose the web application of the environment previews copy that runs them.
  3. Write one command on each line, such as node ace db:seed, then choose Save.

The commands run in their order. The first one that fails stops the others and fails the deployment of the preview: its logs show what the command wrote. The next push runs the setup commands again, until they all succeed once.

A preview opened before the change runs the new setup commands at its next push. Empty the field to run none.

If the environment previews copy no longer has that web application, for example after a rename, new previews fail and say so. Choose another one under Setup.

Pushes to a pull request

Each push to the pull request deploys its last commit in the preview, as deploy on push does: commits pushed during a deployment wait, and only the last one deploys. GitHub shows how each deployment goes beside its commit.

An application bound to a database deploys its first time once that database runs. That first deployment shows no status on GitHub.

Pushes to other branches never deploy into a preview.

Applications from an image

An application deployed from a container image, such as one your GitHub Actions publish to GHCR, deploys nothing when its preview opens: the Previews tab shows Waiting for image. Your CI builds the image of the pull request, then calls the deploy hook of the application in the environment previews copy, with the number of the pull request and the tag of the image, through the Tenkai deploy action. Tenkai deploys that tag of the same image into the preview, with its pre-deploy and setup commands. Each call deploys the tag it names, and the preview keeps it, also when its deployment fails.

A pull request opens a preview only when the environment previews copy runs code of its repository: an application built from it, or a GHCR image named after it, ghcr.io/<owner>/<repository> or ghcr.io/<owner>/<repository>/<name>. A Docker Hub image, or a GHCR image with another name, opens no preview, unless an application of that environment also builds the repository from Git.

  1. Enable the deploy hook of the application in the environment previews copy.
  2. Add its URL and its secret to the secrets of your repository, as TENKAI_DEPLOY_HOOK_URL and TENKAI_DEPLOY_HOOK_SECRET.
  3. Create .github/workflows/preview-image.yml:
name: Preview image

on:
  pull_request:

jobs:
  preview:
    # A fork opens no preview, and gets no secrets.
    if: github.event.pull_request.head.repo.full_name == github.repository
    runs-on: ubuntu-24.04
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v7

      - uses: docker/setup-buildx-action@v4

      - uses: docker/login-action@v4
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - id: meta
        uses: docker/metadata-action@v6
        with:
          images: ghcr.io/${{ github.repository }}
          tags: type=ref,event=pr

      - uses: docker/build-push-action@v7
        with:
          context: .
          platforms: linux/amd64
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

      - uses: TenkaiCloud/deploy-action@v1
        with:
          deploy_hook_url: ${{ secrets.TENKAI_DEPLOY_HOOK_URL }}
          deploy_hook_secret: ${{ secrets.TENKAI_DEPLOY_HOOK_SECRET }}
          pull_request: ${{ github.event.pull_request.number }}
          image_tag: pr-${{ github.event.pull_request.number }}

Each push to the pull request publishes ghcr.io/<owner>/<repository>:pr-<number> and deploys it into the preview. Tenkai pulls the tag again at each call, so pr-<number> deploys the last build. Tenkai refuses another image than the one the application pulls. The action waits for the deployment to end and fails the job when it fails, or when Tenkai refuses the image, with what to do. Publish an image to GHCR explains how to build for your cluster and let Tenkai pull a private image.

The first preview of a project waits about a minute for its database server. If your CI calls the hook before the preview opened, the job fails: run it again.

The comment on the pull request

As soon as Tenkai starts to open a preview, it comments on the pull request. Once the preview is open, the comment shows the URL of each web application of the preview and how its last deployment went, or that it waits for its image. If the preview cannot open, the comment says why. Tenkai updates that one comment after each deployment, also after a preview deleted while idle opens again.

The comment needs the permission to write pull requests of the Tenkai GitHub App. GitHub asks the account owner to accept it, in the settings of the installation. The previews work without it.

Pull requests from a fork

A pull request from a fork gets no preview: its code was written outside your repository, and would run on your cluster.

When a preview failed

The Previews tab says why a preview did not open, such as another environment named pr-12. Fix the cause, then push to the pull request: Tenkai opens the preview again. If the database server that previews share did not start, the push starts it again.

When the last deployment of an application of the preview failed, the tab says why under Failed, such as Setup command failed. Choose the link beside it to open the logs of that deployment, fix the cause, then push to the pull request.

If Tenkai could not delete a preview once its pull request closed, the tab says which resource stayed. Delete that resource, then the environment, from the project.