v1

Infrastructure as Code /

Write a template

Templates are written in JSON, and consist of objects that define:

  • the template structure
  • Northflank resources to create or update
  • conditions to check
  • actions to perform

Templates can be used to create and manage projects, project resources, and team integrations.

When you create a template you can either edit the template as JSON, or use the visual editor to drag and drop nodes. Learn more about creating templates with the Northflank template editor and viewing specifications for your existing projects and resources.

This guide will first introduce best practices for writing templates. It will then run through the structure of a template and how to use node references and arguments, which are important to creating programmatic templates that are easy to modify and reuse. The different types of nodes and their properties will then be detailed, before providing some examples of templates.

You can find more detailed schema for Northflank templates and template nodes in the API documentation for templates.

Properties not mentioned in the application documentation are only applicable to the Northflank API, and should not be included in templates managed using the Northflank application or a Git repository.

Template structure

Your template must include information about the template itself, such as apiVersion and name (and optionally a description).

The spec object contains the body of the template, that is the workflows, conditions, resources, and actions that will be executed during a template run.

If you create or edit a template via the Northflank application you can configure all the template options on the settings page. See the API page for create template for the full specification.

The top level of a template looks like this:

{
  "apiVersion": "v1",
  "name": "template-name",
  "description": "Your template description",
  "concurrencyPolicy": "allow",
  "arguments": {},
  "argumentOverrides": {},
  "options": {
    "autorun": false
  },
  "spec": {
    ...
  }
}

If you are writing a template as a JSON file the required fields, listed in the attributes below, must be included. You can also see the examples further down on this page of complete templates.

  • {object}
    • apiVersion

      string required

      The version of the Northflank API to run the template against.

      one of
      v1, v1.1
    • name

      string required

      Name of the template.

    • description

      string

      Description of the template.

    • concurrencyPolicy

      string

      Defines the concurrency behaviour of the template with respect to parallel runs.

      one of
      forbid, allow, queue
    • arguments

      {object}

      A set of arguments that can be referenced in a template using '${args.argumentName}'.

      • argumentOverrides

        {object}

        Argument overrides stored outside of the template. If GitOps is enabled, these will not be saved in version control.

        • options

          {object}

          Additional options for the template creation.

          • autorun

            boolean

            If true, the template will run automatically whenever it is updated.

        • spec

          {object} required

          Contains nodes representing actions to be performed as part of the template.

        Project context

        Every node for a project-level resource must have a project context. You can either set the project context directly in the resource node specification, or the node can inherit the project context from a parent workflow. You can create and update resources across multiple projects by setting different contexts for workflows or nodes.

        Setting the project context for a workflow in the Northflank application

        You can set the context as an existing project from your team, or create a new project in the template. If you are using a reference to set the project context, the project node must run before the reference is used in the template.

        If you run a template with nodes that require, but do not have, a project context, the template run will fail.

        Set project context on a workflow

        The example below creates a new project with a reference, before defining a workflow with that project as the context. Any resources included in this workflow will be created in that project.

        {
          "apiVersion": "v1.1",
          "spec": {
            "kind": "Workflow",
            "spec": {
              "type": "sequential",
              "context": {},
              "steps": [
                {
                  "kind": "Project",
                  "ref": "project",
                  "spec": {
                    "name": "New Project",
                    "description": "This is a new project.",
                    "color": "#0A5BA5",
                    "region": "europe-west"
                  }
                },
                {
                  "kind": "Workflow",
                  "spec": {
                    "type": "sequential",
                    "context": {
                      "projectId": "${refs.project.id}"
                    },
                    "steps": []
                  }
                }
              ]
            }
          }
        }
        

        Set project context for a node

        Project context can be supplied to nodes in the specification, either as a hardcoded project ID, or as a reference. This will override the project context inherited from a workflow, if any exists.

        {
          "kind": "DeploymentService",
          "spec": {
            "name": "nginx",
            "projectId": "my-project",
            "billing": {
              "deploymentPlan": "nf-compute-50"
            },
            "deployment": {
              "instances": 1,
              "external": {
                "imagePath": "library/nginx:latest"
              }
            },
            "ports": [
              {
                "name": "port-01",
                "internalPort": 80,
                "public": true,
                "protocol": "HTTP"
              }
            ]
          }
        }
        

        Arguments and argument overrides

        You can include arguments in your template, referenced in the format ${args.<argument-name>}, replacing <argument-name> with your key. This is useful if you have a value you wish to dynamically generate, change on subsequent template runs, or which is used repeatedly throughout the template.

        Arguments are stored in the argument object at the top-level of the template as key-value pairs. You can also set argument values in the UI using the template form's arguments override section, however these will not be saved in the template specification.

        It can be useful to include the keys for sensitive data in your arguments object, but you should not include their values.

        Argument overrides

        Argument overrides can be used to inject secure values into your template, or override existing argument values. Argument overrides are stored securely on Northflank, separately from your template.

        Key-value pairs in the argumentOverrides object will override arguments with the same key in the arguments object. If the key specified in the overrides object does not exist in the arguments object, it will be inserted.

        If you are using GitOps these will not be saved in your repository if you add the argument overrides in the Northflank UI using the template form. You should not commit argument overrides in your template.

        You can supply argument overrides using the API by including an argumentOverride object at the top-level of the template, containing the key-value pairs of arguments to override.

        Run on creation overrides

        If you are creating a template using the API you can also specify runOnCreationArgumentOverrides in options, which will only be used when the template is created if runOnCreation is set to true.

        Example

        {
          "name": "Example Template",
          "description": "This is a sample template.",
          "apiVersion": "v1",
          "arguments": {
            "ARGUMENT_1": "default_1",
            "ARGUMENT_2": "default_2",
            "ARGUMENT_3": ""
          },
          "argumentOverrides": {
            "ARGUMENT_1": "hello",
            "ARGUMENT_2": "world",
            "ARGUMENT_3": ""
          },
          "options": {
            "runOnCreation": true,
            "runOnCreationArgumentOverrides": {
              "ARGUMENT_1": "goodnight",
              "ARGUMENT_2": "moon",
              "ARGUMENT_3": ""
            },
            "autorun": false
          },
          "spec": {
            "kind": "Workflow",
            "spec": {
              "type": "sequential",
              "steps": [
                ...
              ]
            }
          }
        }
        

        Node references

        You can add a reference property to nodes which allows you to refer to the output of that node later in the template. References are added to the top-level of a node, in the format "ref": "<string>", where <string> is the name of the reference.

        References to a node return a promise, which resolves to the relevant response from the node. References are accessed in the template using the refs object, in the format ${refs.<reference-name>.<property>}.

        Check the response schemas in the API documentation.

        This is useful if you have steps in your workflow that require confirmation that previous steps have been completed successfully, or details from resources created earlier.

        The example below shows a node to create a build service, and later a node to start a build. In this case ${refs.builder.id} will resolve to my-build-service, which will be the Northflank ID generated from the build service's name. By using the reference to get id you can change the specification of the build service without the need to update the rest of the template.

        "steps": [
          {
            "kind": "BuildService",
            "ref": "builder"
            "spec": {
              "name": "My build service",
              ...
            }
          },
          {
            "kind": "Build",
            "spec": {
              "id": "${refs.builder.id}",
              "type": "service",
              "branch": "main",
              "reuseExistingBuilds": true,
            },
            "condition": "success"
          },
        ]
        

        Northflank DNS references

        You can obtain the public DNS for a service from a reference in the following format: ${refs.<service-name>.ports.<array-number>.dns}. Ports are an array of objects, you must provide the array position of the port you want to get the DNS for. For example if the first port on your service is a public HTTP port, you would obtain the DNS with the following: ${refs.<service-name>.ports.0.dns}.

        If you are using references to obtain the Northflank-generated DNS for a service, or connection details for an addon, you should include a condition node to make sure the service or addon is running. This will ensure the service or addon has obtained a subdomain before using the reference to obtain the DNS or connection details.

        Dynamic domains

        You can dynamically create subdomains in templates by configuring your domain to use wildcard redirect routing and certificate generation when you add it to Northflank.

        You can then use the values from references and arguments to assign subdomains to your services, for example "${args.<argument-name>}.example.com" or "${refs.<reference-name>.<property>}.example.com".

        You can also accept requests to any subdomain of the parent domain using wildcard subdomains.

        Functions

        You can include functions in your template. Functions are called in the format: "${fn.<function-name>(<arguments>)}", for example "${fn.randomSecret(32, 'hex')}".

        Functions are deterministic and will be evaluated on every template run, excluding the randomSecret function.

        Functions can include references and arguments that do not resolve to a value, unlike the top-level of a template where references and arguments must resolve. Unresolved references and arguments will be treated as false if used as boolean arguments.

        Functions are listed below, consisting of the function name, arguments and their types, and the purpose of the function.

        General

        FunctionArgumentsDescription
        randomSecretlength: number, encoding: string: 'base64' or 'hex'Returns a random base64 secret of the given length, and an optional encoding argument, either 'base64' (default) or 'hex'. This secret will be securely stored in the target resource and remain unchanged during subsequent executions of the template, unless it is manually removed.

        String manipulation

        FunctionArgumentsDescription
        toBase64string: stringConverts a UTF-8 encoded string to a base64-encoded string
        fromBase64base64: base64Converts a base64-encoded string to a UTF-8 encoded string
        slugstring: stringConverts a string to a slug (lowercase string with hyphens instead of spaces)
        indexOfstring: string, match: stringReturns the index of the first instance of the substring in the string, or -1 if not found
        searchstring: string, match: string or regexReturns the index of the first pattern match in the string, or -1 for no match
        replaceoriginal: string, match: string or regex, replacement: stringReplace the first match in the original string with the replacement string
        replaceAlloriginal: string, match: string or regex, replacement: stringReplace all instances of the match in the original string with the replacement string
        sliceoriginal: string, startIndex: integer, endIndex: integerReturns the string between the indices of the original string
        lengthstring: stringReturns the length of the string as an integer

        Boolean functions

        Boolean arguments can be provided as truthy and falsy values similar to JavaScript. They can accept booleans, strings, and numbers, and if a reference or argument does not resolve, it will be regarded as false.

        FunctionArgumentsDescription
        notboolean: booleanNot
        orboolean1: boolean, boolean2: boolean, ...Or, accepts any number of arguments
        andboolean1: boolean, boolean2: boolean, ...And, accepts any number of arguments
        ifboolean: boolean, then: any, else: any (optional)If, returns then argument if true, otherwise returns else argument if provided
        eqequal1: any, equal2: any, ...Equals, accepts any number of arguments
        neqnot1: any, not2: any, ...Not equals, accepts any number of arguments
        gtnum1: number, num2: numberGreater than
        ltnum1: number, num2: numberLesser than
        gtenum1: number, num2: numberGreater than or equal to
        ltenum1: number, num2: numberLesser than or equal to

        Maths

        FunctionArgumentsDescription
        adda: number, b: number, ...Add all arguments, accepts any number of arguments
        subtracta: number, b: number, ...Subtract all arguments, accepts any number of arguments
        multiplya: number, b: number, ...Multiply all arguments, accepts any number of arguments
        dividea: number, b: numberDivide a by b
        remaindera: number, b: numberThe remainder of a divided by b
        expa: number, b: numbera to the power of b
        floora: numberThe floor of a
        ceila: numberThe ceiling of a

        Example

        This example template uses references, arguments, and functions to programmatically build and deploy from a Git repository.

        The Git account, repository, and branch are given as arguments to define the service names and retrieve the Git account and repository URL. References are then used to trigger a build and deploy it in the deployment service.

        The resources assigned to the deployment service depend on the name of the branch, combining if and eq functions, as well as passing different runtime variables to the deployment.

        {
          "apiVersion": "v1",
          "spec": {
            "kind": "Workflow",
            "spec": {
              "type": "sequential",
              "steps": [
                {
                  "kind": "BuildService",
                  "ref": "builder",
                  "spec": {
                    "name": "${args.repository}-builder",
                    "billing": {
                      "deploymentPlan": "nf-compute-50"
                    },
                    "vcsData": {
                      "projectUrl": "https://github.com/${args.account}/${args.repository}",
                      "projectType": "github"
                    },
                    "buildSettings": {
                      "dockerfile": {
                        "buildEngine": "kaniko",
                        "dockerFilePath": "/Dockerfile",
                        "dockerWorkDir": "/"
                      }
                    },
                    "buildConfiguration": {
                      "prRestrictions": [
                        "*"
                      ],
                      "branchRestrictions": [
                        "main"
                      ]
                    }
                  }
                },
                {
                  "kind": "Build",
                  "ref": "build",
                  "spec": {
                    "id": "${refs.builder.id}",
                    "type": "service",
                    "branch": "${args.branch}"
                  }
                },
                {
                  "kind": "Condition",
                  "spec": {
                    "kind": "Build",
                    "spec": {
                      "type": "success",
                      "data": {
                        "buildId": "${refs.build.id}"
                      }
                    }
                  }
                },
                {
                  "kind": "DeploymentService",
                  "spec": {
                    "name": "${args.branch}-deployment",
                    "billing": {
                      "deploymentPlan": "${fn.if(fn.eq(args.branch, 'main'), 'nf-compute-100', 'nf-compute-50')}"
                    },
                    "deployment": {
                      "instances": "${fn.if(fn.eq(args.branch, 'main'), 3, 1)}",
                      "docker": {
                        "configType": "default"
                      },
                      "storage": {
                        "ephemeralStorage": {
                          "storageSize": 1024
                        }
                      },
                      "internal": {
                        "id": "${refs.builder.id}",
                        "branch": "${args.branch}",
                        "buildId": "${refs.build.id}"
                      }
                    },
                    "runtimeEnvironment": {
                      "ENVIRONMENT": "${fn.if(fn.eq(args.branch, 'main'), 'production', 'development')}"
                    }
                  }
                }
              ]
            }
          }
        }
        

        Types of node

        The sections below contain information on the available node types that you can include in your template. Each section contains a list of nodes of that type, an example node specification, and references from the API.

        The nodes are divided into the following categories:

        • Workflow contains nodes that are to be run in sequence or parallel
        • Team specifies team-level resources, such as projects and integrations
        • Resource specifies a service, job, addon, or other resource to be created or updated
        • Trigger initiates a task within a service, job, or addon
        • Condition includes a condition node that checks the status of a resource or action
        • Action contains an action node that specifies an action to run on a service, repository, or other entity

        Workflow nodes

        Workflow nodes specify whether the nodes contained within them are executed sequentially, or in parallel.

        You can add nodes to the steps array which will be executed in order in a sequential workflow, or at the same time for a parallel workflow.

        Workflow nodes can be nested. You can, for example, run two sequential workflows simultaneously within a parallel workflow.

        You can give workflow nodes a context, which is a project ID. This can either be a hardcoded project ID (for example "my-project"), or a reference that resolves to a project node's ID (for example "${refs.project.id}". Nodes contained within the workflow will inherit this context if they do not have a context defined themselves.

        Workflow nodes take the following format, where nodes would be specified in the steps array:

        {
          "kind": "workflow",
          "context": {
            "projectId": "<project-id>"
          },
          "spec": {
            "type": "sequential | parallel",
            "steps": []
          }
        }
        
        • {object}

          Workflow node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            Workflow
          • spec

            {object} required

            The specification for the workflow node.

          • skipNodeExecution

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

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

        Team nodes

        Team nodes create and update resources and integrations on the team level. They do not require a project context to run.

        NodeKindDescription
        ProjectProjectCreate or update a project
        BYOC integrationBYOCIntegrationCreate or update a BYOC integration
        BYOC clusterBYOCClusterCreate or update a BYOC cluster and node pools
        Subdomain pathSubdomainPathCreate a path for routing on a subdomain
        TagResourceTagCreate a new tag in the team for tagging resources
        MessageMessageCreate a message on a pull request on a git repository

        The example below creates a new project in the europe-west region on Northflank managed cloud.

        {
          "kind": "Project",
          "ref": "project",
          "spec": {
            "name": "New Project",
            "description": "This is a new project.",
            "color": "#0A5BA5",
            "region": "europe-west"
          }
        }
        

        Project

        • {object}

          Project node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            Project
          • spec

            (multiple options: oneOf) required
          • skipNodeExecution

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

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

        BYOC integration

        • {object}

          BYOCIntegration node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            BYOCIntegration
          • spec

            {object} required

            The specification for the BYOCIntegration node.

          • skipNodeExecution

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

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

        BYOC cluster

        • {object}

          BYOCCluster node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            BYOCCluster
          • spec

            {object} required

            The specification for the BYOCCluster node.

          • skipNodeExecution

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

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

        Subdomain path

        • {object}

          SubdomainPath node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            SubdomainPath
          • spec

            {object} required

            The specification for the SubdomainPath node.

          • skipNodeExecution

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

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

        Tag

        • {object}

          ResourceTag node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            ResourceTag
          • spec

            {object} required

            The specification for the ResourceTag node.

          • skipNodeExecution

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

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

        Message

        Message nodes can be configured to comment on a pull request using rich-text, and include content from arguments and references. This can be used, for example, to alert users that a preview environment has been created, and share links to relevant endpoints for preview and testing.

        • {object}

          Message node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            Message
          • spec

            (multiple options: oneOf) required

            The specification for the Message node.

          • skipNodeExecution

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

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

        Resource nodes

        Resource nodes can be used to create or update services, jobs, addons, and other resources on the Northflank platform. They can also be used to trigger builds, run jobs, and schedule addon backups.

        NodeKindDescription
        Build serviceBuildServiceCreate or update a build service
        Combined serviceCombinedServiceCreate or update a combined service
        Deployment serviceDeploymentServiceCreate or update a deployment service
        Cron jobCronJobCreate or update a cron job
        Manual jobManualJobCreates or update a manual job
        AddonAddonCreates or updates an addon
        Secret groupSecretGroupCreates or updates a secret group
        VolumeVolumeCreates or updates a volume
        BuildBuildTriggers a build in a service or job, from a branch or a specific commit
        Run jobJobRunRuns a job with the specified configuration
        Run backupAddonBackupPerforms a backup on an addon

        The example below creates a deployment service called nginx, deploying the nginx image from Docker Hub . It also publicly exposes port 80 using HTTP. Resource nodes must have a projectId set in the node, or inherit the project context from a workflow.

        {
          "kind": "DeploymentService",
          "spec": {
            "name": "nginx",
            "projectId": "my-project",
            "billing": {
              "deploymentPlan": "nf-compute-50"
            },
            "deployment": {
              "instances": 1,
              "external": {
                "imagePath": "library/nginx:latest"
              }
            },
            "ports": [
              {
                "name": "port-01",
                "internalPort": 80,
                "public": true,
                "protocol": "HTTP"
              }
            ]
          }
        }
        

        Combined service

        • {object}

          CombinedService node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            CombinedService
          • spec

            {object} required

            The specification for the CombinedService node.

          • skipNodeExecution

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

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

        Build service

        • {object}

          BuildService node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            BuildService
          • spec

            {object} required

            The specification for the BuildService node.

          • skipNodeExecution

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

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

        Deployment service

        If you are deploying from a Northflank build service you can toggle between deploying the latest build or the latest commit from the build service.

        Selecting latest build will deploy whatever the service has build most recently, regardless of the commit age. Selecting latest commit will deploy the most recent commit to the branch that has been built by the service.

        • {object}

          DeploymentService node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            DeploymentService
          • spec

            {object} required

            The specification for the DeploymentService node.

          • skipNodeExecution

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

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

        Cron job

        • {object}

          CronJob node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            CronJob
          • spec

            {object} required

            The specification for the CronJob node.

          • skipNodeExecution

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

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

        Manual job

        • {object}

          ManualJob node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            ManualJob
          • spec

            {object} required

            The specification for the ManualJob node.

          • skipNodeExecution

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

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

        Addon

        • {object}

          Addon node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            Addon
          • spec

            (multiple options: anyOf) required

            The specification for the Addon node.

          • skipNodeExecution

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

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

        Secret group

        • {object}

          SecretGroup node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            SecretGroup
          • spec

            {object} required

            The specification for the SecretGroup node.

          • skipNodeExecution

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

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

        Volume

        • {object}

          Volume node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            Volume
          • spec

            {object} required

            The specification for the Volume node.

          • skipNodeExecution

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

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

        Build

        • {object}

          Build node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            Build
          • spec

            {object} required

            The specification for the Build node.

          • skipNodeExecution

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

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

            string
            one of
            success

        Run job

        • {object}

          JobRun node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            JobRun
          • spec

            {object} required

            The specification for the JobRun node.

          • skipNodeExecution

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

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

            string
            one of
            success

        Run backup

        • {object}

          AddonBackup node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            AddonBackup
          • spec

            {object} required

            The specification for the AddonBackup node.

          • skipNodeExecution

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

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

            string
            one of
            success

        Pipeline nodes

        Pipeline nodes are used to create a pipeline in a project and populate the stages of the pipeline with deployment services, jobs, and addons.

        You can also define a preview environment template for the pipeline, and release flow templates for each stage.

        References in nested templates

        References included in preview environment and release flow templates inside your template will not resolve on template runs. This is to avoid any dynamic values set in the included templates being overwritten by the parent template.

        You can add resources to pipeline stages by including them as objects in a stages array in the pipeline node spec with the names Development, Staging, and Production. Each object in the nfObjects array should refer to a resource by id and type ("service", "job", or "addon").

        Pipeline node

        {
          "kind": "Pipeline",
          "spec": {
            "name": "My pipeline",
            "preview": {},
            "stages": [
              {
                "name": "Development",
                "nfObjects": [
                  {
                    "id": "devel-deployment",
                    "type": "service"
                  }
                ],
                "releaseFlow": {}
              },
              {
                "name": "Staging",
                "nfObjects": [
                  {
                    "id": "staging-job",
                    "type": "job"
                  }
                ],
                "releaseFlow": {}
              },
              {
                "name": "Production",
                "nfObjects": [
                  {
                    "id": "production-addon",
                    "type": "addon"
                  }
                ],
                "releaseFlow": {}
              }
            ]
          }
        }
        
        • {object}

          Pipeline node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            Pipeline
          • spec

            {object} required

            The specification for the Pipeline node.

          • skipNodeExecution

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

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

        Preview environment node

        The pipeline specification can include preview, a node with the kind PreviewEnv. The spec for the PreviewEnv node includes apiVersion, spec and triggers, where spec is the content of the preview environment template and triggers is an array of Git triggers.

        {
          "preview": {
            "kind": "PreviewEnv",
            "spec": {
              "apiVersion": "v1.1",
              "spec": {},
              "triggers": []
            }
          }
        }
        
        • {object}

          preview

          • kind

            string

            The kind of node.

            one of
            PreviewEnv
          • spec

            {object} required

            The preview environment template specification.

        Release flow node

        Release flow nodes can be included in pipeline stage objects, and include apiVersion, spec and triggers, where spec is the content of the release flow template and triggers is an array of Git triggers.

        {
          "releaseFlow": {
            "kind": "ReleaseFlow",
            "spec": {
              "apiVersion": "v1.1",
              "spec": {},
              "triggers": []
            }
          }
        }
        
        • {object}

          releaseFlow

          • kind

            string required

            The kind of node.

            one of
            ReleaseFlow
          • spec

            {object} required

            The release flow template specification.

        Condition nodes

        You can use condition nodes to check the status of a resource or action in a template or in an individual workflow. The workflow or template will continue to run until the condition is met, or until it times out.

        In a sequential workflow the condition will stop following steps from running until the condition is met. In a parallel workflow all the steps will run, but the workflow will not be marked as completed unless the condition is met.

        Below is a list of available condition node types you can include in your template. Specific condition nodes must be contained within the parent Condition node.

        NodeKindDescription
        Await conditionConditionContains a condition node that must be met to continue a sequential workflow, or to mark a parallel workflow as successful
        Service conditionServiceContains checks for services
        Addon conditionAddonContains checks for addons
        Backup conditionAddonBackupContains checks for addon backups
        Job run conditionJobRunContains checks for job runs
        Build conditionBuildContains checks for builds
        VCS conditionVCSContains checks for Git repositories

        An example of a condition node specification that checks if the referenced build has completed successfully:

        {
          "kind": "Condition",
          "spec": {
            "kind": "Build",
            "spec": {
              "type": "success",
              "data": {
                "buildId": "${refs.build.id}"
              }
            }
          }
        }
        
        • {object}

          Condition node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            Condition
          • spec

            (multiple options: oneOf) required

            The specification for the Condition node.

          • skipNodeExecution

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

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

        Action nodes

        You can define actions to take on existing services, addons, or Git services using action nodes.

        You can, for example, restart a service or addon, or clone an existing repository into a new one. This can be useful if you have deployed a service that requires restarting after initialising, or want to share a template and enable users to modify the source code.

        Below is a list of available action node types you can include in your template. Specific action nodes must be contained within the parent Action node.

        NodeKindDescription
        ActionActionContains an action node that will perform the specified action on a resource
        Service actionServicePerform an action on a service
        Addon actionAddonPerform an action on an addon
        VCS actionVCSPerform an action on a Git account

        The example below triggers a restart of a service:

        {
          "kind": "Action",
          "spec": {
            "kind": "Service",
            "spec": {
              "type": "restart",
              "data": {
                "serviceId": "service-to-restart"
              }
            }
          }
        }
        

        Execute a command in a service

        {
          "kind": "Action",
          "spec": {
            "kind": "Service",
            "spec": {
              "type": "execute",
              "data": {
                "serviceId": "my-service",
                "command": "sh -c \"echo ${MESSAGE}\""
              }
            }
          }
        }
        

        Commands in action nodes do not invoke a shell by default. Learn more about executing commands in action nodes.

        • {object}

          Action node

          • ref

            string

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

          • kind

            string required

            The kind of node.

            one of
            Action
          • spec

            (multiple options: oneOf) required

            The specification for the Action node.

          • skipNodeExecution

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

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

        Example template

        This template example will guide you through the building of a template to deploy Payload CMS which will:

        1. Define template settings
        2. Create a project and add a workflow with the project context
        3. Deploy an addon and a combined service that builds from a Git repository
        4. Create a secret group to store required environment variables and addon connection details
        5. Build an image from the repository and restart the service when the database is ready

        Define template settings

        The template is defined with the Northflank API version, the name and description for the template, and various options. In the visual editor, these can all be configured on the settings page. The empty spec object will contain our template content.

        {
          "apiVersion": "v1.1",
          "name": "Payload Template",
          "description": "Payload is a headless CMS and application framework built with TypeScript, Node.js, React and MongoDB.",
          "concurrencyPolicy": "queue",
          "arguments": {},
          "argumentOverrides": {},
          "options": {
            "autorun": false
          },
          "spec": {}
        }
        

        Create a project and workflow with project context

        Inside the spec we have added a parent workflow, as all nodes must be contained within a workflow. It's a sequential workflow, so the nodes will be run in order, with the next node only being executed when the previous node has completed successfully.

        Inside the workflow we have added two nodes to the workflow's steps, a project node and a workflow node. The workflow node uses the reference to the project node to get the project context ("${refs.project.id}"). All nodes that create or update project resources within this workflow will execute in this project, unless they are given another context.

        {
          "apiVersion": "v1.1",
          "name": "Payload Template",
          "description": "Payload is a headless CMS and application framework built with TypeScript, Node.js, React and MongoDB.",
          "concurrencyPolicy": "queue",
          "arguments": {},
          "argumentOverrides": {},
          "options": {
            "autorun": false
          },
          "spec": {
            "kind": "Workflow",
            "spec": {
              "type": "sequential",
              "steps": [
                {
                  "kind": "Project",
                  "ref": "project",
                  "spec": {
                    "name": "Payload project",
                    "color": "#7FD1B9",
                    "region": "europe-west",
                    "description": "My example Payload project"
                  }
                },
                {
                  "kind": "Workflow",
                  "spec": {
                    "type": "sequential",
                    "context": {
                      "projectId": "${refs.project.id}"
                    },
                    "steps": []
                  }
                }
              ]
            }
          }
        }
        

        Deploy an addon and combined service

        We then add two nodes to the workflow node with the project context, a node to create a MongoDB addon with the reference database and a node to create a combined service with the reference payload. The combined service deploys the master branch from the repository https://github.com/northflank-guides/deploy-payload-on-northflank.

        {
          "apiVersion": "v1.1",
          "name": "Payload Template",
          "description": "Payload is a headless CMS and application framework built with TypeScript, Node.js, React and MongoDB.",
          "concurrencyPolicy": "queue",
          "arguments": {},
          "argumentOverrides": {},
          "options": {
            "autorun": false
          },
          "spec": {
            "kind": "Workflow",
            "spec": {
              "type": "sequential",
              "steps": [
                {
                  "kind": "Project",
                  "ref": "project",
                  "spec": {
                    "name": "Payload project",
                    "color": "#7FD1B9",
                    "region": "europe-west",
                    "description": "My example Payload project"
                  }
                },
                {
                  "kind": "Workflow",
                  "spec": {
                    "type": "sequential",
                    "context": {
                      "projectId": "${refs.project.id}"
                    },
                    "steps": [
                      {
                        "kind": "Addon",
                        "ref": "database",
                        "spec": {
                          "name": "Database",
                          "type": "mongodb",
                          "version": "7.0-latest",
                          "billing": {
                            "deploymentPlan": "nf-compute-20",
                            "storageClass": "ssd",
                            "storage": 4096,
                            "replicas": 1
                          },
                          "tlsEnabled": true,
                          "externalAccessEnabled": false,
                          "ipPolicies": [],
                          "pitrEnabled": false
                        }
                      },
                      {
                        "kind": "CombinedService",
                        "ref": "payload",
                        "spec": {
                          "name": "Payload",
                          "deployment": {
                            "instances": 1,
                            "storage": {
                              "ephemeralStorage": {
                                "storageSize": 1024
                              },
                              "shmSize": 64
                            },
                            "docker": {
                              "configType": "default"
                            }
                          },
                          "billing": {
                            "deploymentPlan": "nf-compute-20"
                          },
                          "ports": [
                            {
                              "name": "app",
                              "internalPort": 3000,
                              "public": true,
                              "protocol": "HTTP",
                              "security": {
                                "credentials": [],
                                "policies": []
                              },
                              "domains": []
                            }
                          ],
                          "vcsData": {
                            "projectUrl": "https://github.com/northflank-guides/deploy-payload-on-northflank",
                            "projectType": "github",
                            "projectBranch": "master"
                          },
                          "buildSettings": {
                            "dockerfile": {
                              "buildEngine": "kaniko",
                              "dockerFilePath": "/Dockerfile",
                              "dockerWorkDir": "/"
                            }
                          },
                          "runtimeEnvironment": {},
                          "runtimeFiles": {},
                          "buildArguments": {},
                          "buildFiles": {},
                          "disabledCI": false,
                          "buildConfiguration": {
                            "pathIgnoreRules": [],
                            "isAllowList": false,
                            "ciIgnoreFlagsEnabled": false
                          }
                        }
                      }
                    ]
                  }
                }
              ]
            }
          }
        }
        

        Create a secret group

        We now add a secret group in the workflow to contain environment variables that the Payload application. These variables are:

        1. PAYLOAD_PUBLIC_BASE_DNS

        This variable gets the Northflank-generated domain name for the Payload port using the reference "https://${refs.payload.ports.0.dns}", with the required https:// protocol added.

        1. PAYLOAD_SECRET

        This is a random secret value used to encrypt Payload API keys. The value in the secret group is obtained from the template arguments object, using "${args.PAYLOAD_SECRET}". The secret is generated using the Northflank function "${fn.randomSecret(256)}" in the template's argument overrides. Once generated, it will be securely stored on Northflank so future template runs do not overwrite the value. All sensitive secrets should be stored as argument overrides, and not within the template or as template arguments, as these are not secure.

        1. MONGODB_URI

        The URI for the MongoDB addon is obtained using the reference to the addon, "${refs.database.id}", and setting MONGODB_URI as an alias of the Northflank-defined key MONGO_SRV.

        {
          "apiVersion": "v1.1",
          "name": "Payload Template",
          "description": "Payload is a headless CMS and application framework built with TypeScript, Node.js, React and MongoDB.",
          "concurrencyPolicy": "queue",
          "arguments": {
            "PAYLOAD_SECRET": ""
          },
          "argumentOverrides": {
            "PAYLOAD_SECRET": "${fn.randomSecret(256)}"
          },
          "options": {
            "autorun": false
          },
          "spec": {
            "kind": "Workflow",
            "spec": {
              "type": "sequential",
              "steps": [
                {
                  "kind": "Project",
                  "ref": "project",
                  "spec": {
                    "name": "Payload project",
                    "color": "#7FD1B9",
                    "region": "europe-west",
                    "description": "My example Payload project"
                  }
                },
                {
                  "kind": "Workflow",
                  "spec": {
                    "type": "sequential",
                    "context": {
                      "projectId": "${refs.project.id}"
                    },
                    "steps": [
                      {
                        "kind": "Addon",
                        "ref": "database",
                        "spec": {
                          "name": "Database",
                          "type": "mongodb",
                          "version": "7.0-latest",
                          "billing": {
                            "deploymentPlan": "nf-compute-20",
                            "storageClass": "ssd",
                            "storage": 4096,
                            "replicas": 1
                          },
                          "tlsEnabled": true,
                          "externalAccessEnabled": false,
                          "ipPolicies": [],
                          "pitrEnabled": false
                        }
                      },
                      {
                        "kind": "CombinedService",
                        "ref": "payload",
                        "spec": {
                          "name": "Payload",
                          "deployment": {
                            "instances": 1,
                            "storage": {
                              "ephemeralStorage": {
                                "storageSize": 1024
                              },
                              "shmSize": 64
                            },
                            "docker": {
                              "configType": "default"
                            }
                          },
                          "billing": {
                            "deploymentPlan": "nf-compute-20"
                          },
                          "ports": [
                            {
                              "name": "app",
                              "internalPort": 3000,
                              "public": true,
                              "protocol": "HTTP",
                              "security": {
                                "credentials": [],
                                "policies": []
                              },
                              "domains": []
                            }
                          ],
                          "vcsData": {
                            "projectUrl": "https://github.com/northflank-guides/deploy-payload-on-northflank",
                            "projectType": "github",
                            "projectBranch": "master"
                          },
                          "buildSettings": {
                            "dockerfile": {
                              "buildEngine": "kaniko",
                              "dockerFilePath": "/Dockerfile",
                              "dockerWorkDir": "/"
                            }
                          },
                          "runtimeEnvironment": {},
                          "runtimeFiles": {},
                          "buildArguments": {},
                          "buildFiles": {},
                          "disabledCI": false,
                          "buildConfiguration": {
                            "pathIgnoreRules": [],
                            "isAllowList": false,
                            "ciIgnoreFlagsEnabled": false
                          }
                        }
                      },
                      {
                        "kind": "SecretGroup",
                        "spec": {
                          "name": "secrets",
                          "secretType": "environment-arguments",
                          "priority": 10,
                          "secrets": {
                            "variables": {
                              "PAYLOAD_PUBLIC_BASE_DNS": "https://${refs.payload.ports.0.dns}",
                              "PAYLOAD_SECRET": "${args.PAYLOAD_SECRET}"
                            }
                          },
                          "addonDependencies": [
                            {
                              "addonId": "${refs.database.id}",
                              "keys": [
                                {
                                  "keyName": "MONGO_SRV",
                                  "aliases": [
                                    "MONGODB_URI"
                                  ]
                                }
                              ]
                            }
                          ],
                          "restrictions": {
                            "restricted": false,
                            "nfObjects": [],
                            "tags": []
                          }
                        }
                      }
                    ]
                  }
                }
              ]
            }
          }
        }
        

        Restart the service when the database is ready

        Next we add another workflow node. This is a parallel workflow, so it will execute both the node simultaneously. Once both nodes have successfully completed, the workflow will be marked as completed and the next node in the sequential workflow will run.

        Inside the parallel workflow are two condition nodes, one checks that the addon has finished provisioning and is ready to use, and the other checks that the combined service is running, which means it has built and deployed an image.

        Finally, we add an action node to restart the service to ensure it is deployed with the necessary environment variables from the secret group.

        {
          "apiVersion": "v1.1",
          "name": "Payload Template",
          "description": "Payload is a headless CMS and application framework built with TypeScript, Node.js, React and MongoDB.",
          "concurrencyPolicy": "queue",
          "arguments": {
            "PAYLOAD_SECRET": ""
          },
          "argumentOverrides": {
            "PAYLOAD_SECRET": "${fn.randomSecret(256)}"
          },
          "options": {
            "autorun": false
          },
          "spec": {
            "kind": "Workflow",
            "spec": {
              "type": "sequential",
              "steps": [
                {
                  "kind": "Project",
                  "ref": "project",
                  "spec": {
                    "name": "Payload project",
                    "color": "#7FD1B9",
                    "region": "europe-west",
                    "description": "My example Payload project"
                  }
                },
                {
                  "kind": "Workflow",
                  "spec": {
                    "type": "sequential",
                    "context": {
                      "projectId": "${refs.project.id}"
                    },
                    "steps": [
                      {
                        "kind": "Addon",
                        "ref": "database",
                        "spec": {
                          "name": "Database",
                          "type": "mongodb",
                          "version": "7.0-latest",
                          "billing": {
                            "deploymentPlan": "nf-compute-20",
                            "storageClass": "ssd",
                            "storage": 4096,
                            "replicas": 1
                          },
                          "tlsEnabled": true,
                          "externalAccessEnabled": false,
                          "ipPolicies": [],
                          "pitrEnabled": false
                        }
                      },
                      {
                        "kind": "CombinedService",
                        "ref": "payload",
                        "spec": {
                          "name": "Payload",
                          "deployment": {
                            "instances": 1,
                            "storage": {
                              "ephemeralStorage": {
                                "storageSize": 1024
                              },
                              "shmSize": 64
                            },
                            "docker": {
                              "configType": "default"
                            }
                          },
                          "billing": {
                            "deploymentPlan": "nf-compute-20"
                          },
                          "ports": [
                            {
                              "name": "app",
                              "internalPort": 3000,
                              "public": true,
                              "protocol": "HTTP",
                              "security": {
                                "credentials": [],
                                "policies": []
                              },
                              "domains": []
                            }
                          ],
                          "vcsData": {
                            "projectUrl": "https://github.com/northflank-guides/deploy-payload-on-northflank",
                            "projectType": "github",
                            "projectBranch": "master"
                          },
                          "buildSettings": {
                            "dockerfile": {
                              "buildEngine": "kaniko",
                              "dockerFilePath": "/Dockerfile",
                              "dockerWorkDir": "/"
                            }
                          },
                          "runtimeEnvironment": {},
                          "runtimeFiles": {},
                          "buildArguments": {},
                          "buildFiles": {},
                          "disabledCI": false,
                          "buildConfiguration": {
                            "pathIgnoreRules": [],
                            "isAllowList": false,
                            "ciIgnoreFlagsEnabled": false
                          }
                        }
                      },
                      {
                        "kind": "SecretGroup",
                        "spec": {
                          "name": "secrets",
                          "secretType": "environment-arguments",
                          "priority": 10,
                          "secrets": {
                            "variables": {
                              "PAYLOAD_PUBLIC_BASE_DNS": "https://${refs.payload.ports.0.dns}",
                              "PAYLOAD_SECRET": "${args.PAYLOAD_SECRET}"
                            }
                          },
                          "addonDependencies": [
                            {
                              "addonId": "${refs.database.id}",
                              "keys": [
                                {
                                  "keyName": "MONGO_SRV",
                                  "aliases": [
                                    "MONGODB_URI"
                                  ]
                                }
                              ]
                            }
                          ],
                          "restrictions": {
                            "restricted": false,
                            "nfObjects": [],
                            "tags": []
                          }
                        }
                      },
                      {
                        "kind": "Workflow",
                        "spec": {
                          "type": "parallel",
                          "steps": [
                            {
                              "kind": "Condition",
                              "spec": {
                                "kind": "Addon",
                                "spec": {
                                  "type": "running",
                                  "data": {
                                    "addonId": "${refs.database.id}"
                                  }
                                }
                              }
                            },
                            {
                              "kind": "Condition",
                              "spec": {
                                "kind": "Service",
                                "spec": {
                                  "type": "running",
                                  "data": {
                                    "addonId": "${refs.payload.id}"
                                  }
                                }
                              }
                            }
                          ]
                        }
                      },
                      {
                        "kind": "Action",
                        "spec": {
                          "kind": "Service",
                          "spec": {
                            "type": "restart",
                            "data": {
                              "serviceId": "${refs.payload.id}"
                            }
                          }
                        }
                      }
                    ]
                  }
                }
              ]
            }
          }
        }
        

        © 2024 Northflank Ltd. All rights reserved.