v1

Release /

Set up a preview environment

You can preview your changes on Git branches and PRs with ephemeral environments, configured in your pipelines.

Preview environments can automatically build your latest changes and deploy them, either in an entirely self-contained environment, or one that shares resources with your existing development environment.

A new preview environment will be created automatically when you push a commit to a branch or open a pull request that matches your Git triggers. If the branch already has a preview environment, the existing preview environment will be updated. You can also use a webhook to create a new preview environment, or create one manually.

Creating a new preview environment template using the visual editor in the Northflank application.

Preview environments are defined using Northflank templates to provision resources and to build and deploy your commits. They use existing build services from your project to build the branch or PR for preview.

You can use trigger references, node references, and arguments to programmatically provision resources for your preview environment, and resources created by the preview environment are tagged for easy identification and teardown.

To configure a preview environment, open a new or existing pipeline in your project and click the configure button add preview template. When you create a new preview environment template it will guide you through selecting a naming convention and a Git trigger, and automatically create a build on trigger node in your template.

Click here to select a pipeline and create a preview environment in it.

You can edit an existing preview environment configuration with the settings button.

Choose a naming convention

When you create a new preview environment you will be prompted to choose a naming convention. You can change the naming convention in the preview environment template settings.

The naming convention for a preview environment will determine the name of the preview environment and resources within it, to distinguish the preview environment from your permanent project resources.

ConventionDescription
Pull request IDUses the ID of the pull request that triggered the preview environment, for example pr-1234
Branch nameUses the name of the branch that the preview environment is based on, for example feature-new-ui. Branch names will be slugified, removing any slashes and other non-alphanumeric characters
TimestampUses the current date and time in the format yy-mm-dd-hhmm, for example 24-01-31-1301
Random wordsUses the Northflank name generator to provide two random words, for example general-question

You can then choose whether the generated portion of the name will be attached to the start (prefix) or the end (suffix) of the names for your resources.

The name of a preview environment is available within the preview environment template as the argument name, accessible in the format ${args.name}.

Any names you assign to resources in the preview environment template (using the visual editor) will automatically have the naming convention applied when the template is run.

Naming conventionPreview environment nameResource nameResource name template valueResulting name
Pull request ID (suffix)pr-439databasedatabase-${args.name}database-pr-439

If a run is triggered by an event that does not match your selected convention the preview will use a randomly-generated name instead.

Add a Git trigger

You can add Git triggers that will create a new preview environment when a commit is pushed to a branch or pull request that matches the trigger. If a preview environment already exists for the branch or pull request, the template will re-run to build and deploy the new commit and update the environment's resources.

You will be prompted to add one or more Git triggers when you create your preview environment template. You can also add or remove Git triggers in the visual editor, and click on an existing trigger to edit it.

To configure a Git trigger, select the repository you want to trigger preview environments for. The trigger will be given a reference based on the repository name to access it in the template.

You can choose to create new preview environments based on all pull requests, which will trigger when a new PR is opened or a commit is pushed to a branch with an open PR. You can also trigger on all branches, which will create a preview environment for any branch in your repository when a commit is pushed to it.

The values from the triggers can be used in your template to build and deploy the desired commit using build on trigger nodes. Northflank will automatically add build on trigger nodes for each trigger you add when you create a new preview environment.

Custom rules

You can define custom pull request and branch rules instead of creating a new preview environment for all branches or pull requests. Branch rules will run the template when a commit is pushed to a branch matching the given rules. Pull request rules will run the template whenever a pull request is opened for a branch matching the given rules, or a commit is pushed to a branch matching the given rules with an open pull request.

You can also add path rules and ignore flags to only create a preview when changes are made to specific files, or to skip runs when a certain commit message is included.

Reference triggers in your template

Git trigger references take the format ${refs.<git-trigger-name>.<key>} and can return the following values:

KeyValue
branchThe name of the branch that triggered the preview environment
shaThe SHA to identify the specific commit to be built
repoUrlThe URL of the repository specified in the Git trigger

Build on trigger

The build on trigger node uses an existing build service to build a commit when it is triggered by the selected Git trigger. You can add multiple build on trigger nodes to handle multiple repositories. For most use cases the repository for the build service and the repository for the trigger should be the same.

The node will use the branch and commit passed by the trigger. You can specify a default branch and commit to use if your template has multiple triggers and build on trigger nodes, or for manually created previews or webhook triggers with no branch or sha arguments provided. You can also select the branch and commit for each node when manually creating a new preview environment.

Editing a build on trigger node in a preview environment template using the visual editor in the Northflank application.

After adding a build on trigger node you can use the deploy to service or deploy to job to create a deployment service or job that uses the build from the build on trigger node.

note

The build on trigger node will not override the repository of the chosen build service. The build service will attempt to build the branch specified by the provided trigger, if it does not exist on the build service repository the build will fail.

The node has the following configurable settings:

OptionDescription
Build service (required)The build service to use to build the image
Trigger (required)A Git trigger specified in the preview environment settings
ReferenceA reference to refer to the node and its outputs later in the template, generated automatically from the repository name
Default branch (advanced)Select a Git repository branch to build from by default if the template is run is caused by a different trigger
Default commit (advanced)Select a Git commit to build by default, if the template is run is caused by a different trigger. If left blank, the latest commit to the branch will be built
Build configuration (advanced)Preview and override build arguments to be used
Reuse existing buildsUse an existing build for the commit if one is available, otherwise a new build will be triggered
Wait for completionIf selected, the next node or workflow will not run until the build has completed
Skip node executionUse references, functions, or arguments that resolve to a boolean to conditionally skip the node
  • {object}

    BuildSource node

    • ref

      string

      An identifier that can used to reference the output of this node later in the PreviewEnvTemplate.

    • kind

      string required

      The kind of node.

      one of
      BuildSource
    • spec

      {object} required

      The specification for the BuildSource node.

    • condition

      string
      one of
      success
    • skipNodeExecution

      (multiple options: oneOf)
      • string
        one of
        true, false
      • OR

      • string
        pattern
        .*\${.*}.*

An example of a build on trigger node specification, which obtains the branch and sha to build from a trigger called application. It will use the main branch by default, it will use an existing build of the commit if one is available, and will wait until the build has completed before allowing the template to progress. It does not pass any build overrides, so the build service will use the default configuration.

{
  "kind": "BuildSource",
  "ref": "build",
  "spec": {
    "type": "service",
    "id": "<build service>",
    "branch": "${refs.application.branch}",
    "sha": "${refs.application.sha}",
    "defaults": {
      "branch": "main"
    },
    "reuseExistingBuilds": true,
    "buildOverrides": {
      "buildArguments": {}
    }
  },
  "condition": "success"
}

Configure a preview environment template

Your preview environment should have one or more triggers, with one or more corresponding build on trigger nodes. Alternatively, you can a webhook trigger or create the environment manually, passing in the required branch and sha values as arguments.

You can then deploy the new builds from the build on trigger nodes in deployment service nodes, or using job nodes.

You can add nodes for the other resources required in your environment, such as addons, secret groups. You can base these on existing resources in your project by copying their specification and pasting the code into a new node.

Depending on your requirements you may want to duplicate your entire development environment, including databases, services, and jobs, or deploy some resources for the preview environment and share databases and jobs with your permanent environment.

Dynamic domains

You can use path-based routing to create new paths for your preview deployments, which does not require certificate generation and does not risk hitting domain certificate rate limits. You can configure a domain to use wildcard redirect routing and certificate generation to dynamically create subdomains in preview environment templates.

When you saved your preview environment template Northflank will create a preview environment for each branch that matches your Git triggers when they receive a new commit.

You can choose how a template will behave if it receives more than one request to run at the same time, or receives a request to run while a run is still in progress. You can set the run concurrency on the template's settings page.

  • Allow (default): multiple template runs can be executed in parallel, with no restrictions
  • Queue: each time a template run is triggered it will be added to a queue, and runs will be executed sequentially in order of creation
  • Forbid: if a template is currently pending or running any run requests will be ignored

You may want to queue or forbid simultaneous runs to ensure that resources are not updated with conflicting configurations.

Manage preview environments

With your Git trigger and preview environment template configured, Northflank will automatically create new preview environments for branches that match your branch and pull request trigger rules. If you have configured a webhook trigger, a new preview environment will be created when you send a request to the webhook URL, and you can use the branch and sha query parameters to trigger a build for the desired commit.

Updating preview environment templates

If you update your preview environment template while there are existing environments, please note that when the preview is next triggered:

  • Resources with the same ID (name) will be updated with the new values in the template
  • If the new template changes values that cannot be patched the template run will fail and the existing preview environment will not be updated
  • Existing resources will not be automatically deleted and if you have changed resource names in the template, the new resources will be created alongside the existing ones

You can pause triggers for a preview environment in the header of the preview environment settings. While paused, Git triggers will be inactive and requests to the webhook will return the HTTP status 202, with a message explaining the trigger is paused. Preview environments can still be created manually while triggers are paused.

All resources created by the preview environment will be tagged with the environment name. You are unable to assign or manage tags created by a preview environment, and they will be deleted when the environment is deleted.

You can see a list of preview environments created in your pipeline, with the repository, branch, and status for each environment. Click through to a preview environment to see the status of the template run and resources associated with the environment.

Resources

Resources for a preview environment, including services, jobs, addons, and secret groups, will be added to the list as they are created by the template. You can view the status of resources created by the preview environment, pause and resume them, and click through to manage them where required.

View runs

You can view a list of template runs for the preview environment, and click through to see the status and results of specific nodes in the template. A new template run for a preview environment will be triggered if a new commit is pushed to the same branch.

Settings

You can delete your preview environment from the settings page.

Inject secrets securely and share environment resources

You can provide secrets to preview environment resources by creating a secret group and restricting it by tag. Create a new tag for your preview environment, and ensure your secret group is restricted to this tag. Add the tag to any resources in your preview environment template you want to inherit from the secret group.

Share secrets

You can share secrets from a development or staging environment with your preview environment by using secret groups that are restricted by tag. Add the relevant tag to preview environment resources and they will also inherit secrets from the restricted group.

You can create a new secret group in your preview environment and link it to an existing addon to share connection details. The new secret group will be restricted to resources tagged with the preview environment ID by default.

Preview environments will also inherit from any unrestricted secret groups in your project.

Share resources

You can use existing permanent resources from your project in your preview environments, such as build services, databases, and jobs.

For example, build on trigger nodes use existing build services, you can run a job with overrides, or execute a command in a running service.

You can provide the connection details for an existing database via an existing secret group, so that your preview environment can use the database in your development environment, for example. Alternatively, create a new secret group in your template and link the existing addon. The secret group will be restricted to resources tagged with the preview environment ID by default.

You can back up and create a fork of an existing database, so that the original database in your permanent environment is unaffected by any changes (for example migrations) in the preview branch.

Create a preview environment using a webhook

You can also use a webhook trigger to create preview environments. Enable the webhook trigger and trigger it by making either a GET or POST request. You can include query parameters at the end of the webhook URL to pass values as arguments.

Webhook trigger query parameters are passed directly to your template as arguments.

For example, triggering a webhook endpoint with the query parameters branch, sha, and foo: https://api-platform.northflank.com/webhooks/release-flows/<TOKEN>?branch=<BRANCH>&sha=<SHA>&foo=<FOO> will make the values accessible in your template as ${args.branch}, ${args.sha}, ${args.foo}.

Create a preview environment manually

You can click create preview in your pipeline to run your preview environment template manually.

You will be prompted to select the branches and commits to use from the repository for each Git trigger. You can also override any arguments for the template. Manually-created preview environments will be given a random name.

CI/CD is disabled for any manually-created environments, meaning it will not be updated when commits are pushed to the previewed branch. You can update the preview environment by creating a new preview with the same branch, which will run the preview template again.

Pause preview environment triggers

You can pause triggers for a preview environment in the header of the template editor.

This will suspend all Git and webhook triggers, and preview environments will not be automatically provisioned until you enable the triggers again.

Delete a preview environment

If the preview environment has been created by a pull request trigger, the environment will be deleted when the pull request is closed or merged. A preview environment created by a branch trigger will be deleted if the branch is deleted. You can manually delete a preview environment from its settings page.

Deleting a preview environment will remove all the resources generated by the template and remove the preview environment entirely from your pipeline. If a new commit is pushed that matches the Git trigger, a new preview environment will be created for the branch.

Preview environment tags will only be deleted when a preview environment is automatically or manually deleted.

Example preview environment template

This example preview environment template has two Git triggers configured to build on any pull request to the selected repositories, configured in the triggers array.

The template starts with a parallel workflow containing two build on trigger nodes and a backup node, which triggers a snapshot of an existing addon (postgres-demo).

After the backup has completed a new addon is deployed as a fork of the existing addon, using the addon ID and the latest backup. A secret group is then created with connection details for the ephemeral preview environment addon. These secrets are restricted to resources that have the preview environment tag.

Finally, two deployment services are deploying the builds created by the build on trigger nodes. The Redis deployment includes the existing tag devel-redis, so that it can inherit the secrets for a permanent resource in the project and share the addon with the development environment, rather than creating a new one for each preview environment.

A preview environment template in the visual editor in the Northflank application.
{
  "apiVersion": "v1.2",
  "triggers": [
    {
      "accountLogin": "northflank-platform",
      "vcsService": "github",
      "repoUrl": "https://github.com/northflank-platform/postgres-demo",
      "branchRestrictions": [],
      "prRestrictions": [
        "*"
      ],
      "pathIgnoreRules": [],
      "isAllowList": false,
      "ciIgnoreFlagsEnabled": true,
      "ciIgnoreFlags": [
        "[skip ci]",
        "[ci skip]",
        "[no ci]",
        "[skip nf]",
        "[nf skip]",
        "[northflank skip]",
        "[skip northflank]"
      ],
      "ref": "postgres-demo",
      "manualOnly": false,
      "id": "<trigger-ID>"
    },
    {
      "accountLogin": "northflank-platform",
      "vcsService": "github",
      "repoUrl": "https://github.com/northflank-platform/redis-demo",
      "branchRestrictions": [],
      "prRestrictions": [
        "*"
      ],
      "pathIgnoreRules": [],
      "isAllowList": false,
      "ciIgnoreFlagsEnabled": true,
      "ciIgnoreFlags": [
        "[skip ci]",
        "[ci skip]",
        "[no ci]",
        "[skip nf]",
        "[nf skip]",
        "[northflank skip]",
        "[skip northflank]"
      ],
      "ref": "redis-demo",
      "manualOnly": false,
      "id": "<trigger_ID>"
    }
  ],
  "spec": {
    "kind": "Workflow",
    "spec": {
      "type": "sequential",
      "steps": [
        {
          "kind": "Workflow",
          "spec": {
            "type": "parallel",
            "steps": [
              {
                "kind": "BuildSource",
                "ref": "build-source-1",
                "spec": {
                  "defaults": {},
                  "reuseExistingBuilds": true,
                  "branch": "${refs.postgres-demo.branch}",
                  "id": "build-postgres-demo",
                  "type": "service",
                  "sha": "${refs.postgres-demo.sha}"
                },
                "condition": "success"
              },
              {
                "kind": "BuildSource",
                "ref": "build-source-2",
                "spec": {
                  "defaults": {},
                  "reuseExistingBuilds": true,
                  "branch": "${refs.redis-demo.branch}",
                  "id": "build-redis-demo",
                  "type": "service",
                  "sha": "${refs.redis-demo.sha}"
                },
                "condition": "success"
              },
              {
                "kind": "AddonBackup",
                "spec": {
                  "addonId": "postgres-demo",
                  "backupType": "snapshot"
                },
                "condition": "success"
              }
            ]
          }
        },
        {
          "kind": "Addon",
          "spec": {
            "name": "${args.name}-postgres",
            "tags": [
              "${args.previewId}"
            ],
            "externalAccessEnabled": false,
            "type": "postgresql",
            "billing": {
              "replicas": 1,
              "storage": 4096,
              "storageClass": "ssd",
              "deploymentPlan": "nf-compute-200"
            },
            "typeSpecificSettings": {
              "postgresqlConnectionPoolerReplicas": 2,
              "postgresqlReadConnectionPoolerReplicas": 2
            },
            "tlsEnabled": true,
            "version": "16",
            "source": {
              "addonId": "postgres-demo",
              "backupId": "latest"
            }
          },
          "ref": "postgres-addon"
        },
        {
          "kind": "SecretGroup",
          "spec": {
            "type": "secret",
            "secretType": "environment-arguments",
            "priority": 10,
            "name": "${args.name}-secrets",
            "tags": [
              "${args.previewId}"
            ],
            "secrets": {
              "variables": {},
              "files": {}
            },
            "restrictions": {
              "restricted": true,
              "tags": [
                "${args.previewId}"
              ],
              "nfObjects": []
            },
            "addonDependencies": [
              {
                "addonId": "${refs.postgres-addon.id}",
                "keys": [
                  {
                    "keyName": "HOST",
                    "aliases": []
                  },
                  {
                    "keyName": "POSTGRES_URI",
                    "aliases": [
                      "POSTGRES_URL"
                    ]
                  },
                  {
                    "keyName": "USERNAME",
                    "aliases": []
                  },
                  {
                    "keyName": "PASSWORD",
                    "aliases": []
                  },
                  {
                    "keyName": "DATABASE",
                    "aliases": []
                  }
                ]
              }
            ]
          },
          "ref": "secrets"
        },
        {
          "kind": "Workflow",
          "spec": {
            "type": "parallel",
            "steps": [
              {
                "kind": "DeploymentService",
                "spec": {
                  "deployment": {
                    "instances": 1,
                    "storage": {
                      "ephemeralStorage": {
                        "storageSize": 1024
                      },
                      "shmSize": 64
                    },
                    "docker": {
                      "configType": "default"
                    },
                    "internal": {
                      "id": "${refs.build-source-1.nfObjectId}",
                      "branch": "${refs.build-source-1.branch}"
                    }
                  },
                  "name": "${args.name}-demo",
                  "tags": [
                    "${args.previewId}"
                  ],
                  "runtimeEnvironment": {},
                  "runtimeFiles": {},
                  "billing": {
                    "deploymentPlan": "nf-compute-20"
                  },
                  "ports": []
                },
                "ref": "demo"
              },
              {
                "kind": "DeploymentService",
                "spec": {
                  "deployment": {
                    "instances": 1,
                    "storage": {
                      "ephemeralStorage": {
                        "storageSize": 1024
                      },
                      "shmSize": 64
                    },
                    "docker": {
                      "configType": "default"
                    },
                    "internal": {
                      "id": "${refs.build-source-2.nfObjectId}",
                      "branch": "${refs.build-source-2.branch}"
                    }
                  },
                  "name": "${args.name}-redis",
                  "tags": [
                    "${args.previewId}",
                    "devel-redis"
                  ],
                  "runtimeEnvironment": {},
                  "runtimeFiles": {},
                  "billing": {
                    "deploymentPlan": "nf-compute-20"
                  },
                  "ports": []
                },
                "ref": "redis-demo"
              }
            ]
          }
        }
      ]
    }
  },
  "options": {
    "concurrencyPolicy": "allow"
  }
}

© 2024 Northflank Ltd. All rights reserved.