Write a template | Infrastructure as Code | Northflank Application docs
v1

Infrastructure as Code /

Write a template

Templates are JSON definitions that consist of different types of nodes which specify workflows, resources, actions or conditions. When you create a template you can either edit the template JSON as a whole, or use the visual editor to drag and drop nodes.

You can edit individual nodes in the visual editor using the form view or switch to code view, which is especially useful to paste in resource specifications.

You can create simple templates from your project specifications in order to duplicate or update your existing resources. You can combine this with GitOps to manage your resources as code, for example your can scale up a deployment or change network configuration by pushing an updated template to your repository.

However, you can create templates that are more easily managed and updated by replacing hard-coded values with references and arguments, which can dynamically populate the template when it is run. This becomes especially useful if you are working with a large, complex template, or want to share your template so others can use and modify it. You can also use functions to return different values based on arguments or other variables, for example assigning a different domain to a port depending on the branch name.

This guide will first introduce best practices for writing templates, and how to get automatically generated template specifications from your existing resources and projects. 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 specifications

The simplest way to start writing a template is to get the template specification for your existing resources or an entire project.

You can also create new projects or resources in order to copy the specification for use in a template, rather than writing the specification from scratch.

View project template

You can click the options button in the project header to get the template for an entire project.

Select view project template to see the specification for your entire project. You can copy this and use the content to create a new template, and edit it where required.

An example of a project template specification in the Northflank application

View resource specification

To view the specification for individual resources, such as services, addons, jobs you can click the options button in the resource's header.

Select view specification and ensure the view is toggled to template. You can copy the specification and insert it into your template.

An example of a service template specification in the Northflank application

Template structure

Your template must include information about the template itself, such as apiVersion and name (and optionally a description). You must also include a project object, which defines the project to create or update, or an existing project ID to run the template in, and the spec object, which contains the workflows, conditions, resources, and actions of the template. You can also include concurrencyPolicy, argumentOverrides, and options objects

If you create or edit a template via the Northflank application all fields except apiVersion and spec are configured in the form, and are hidden from the JSON view. The Northflank editor also includes code hints, autocompletion, and error checking to help you include required properties in the correct format.

The top level of a template looks like this:

{
  "apiVersion": "v1",
  "name": "template-name",
  "description": "Your template description",
  "project": {},
  "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
    • name

      string required

      Name of the template.

    • description

      string

      Description of the template.

    • project

      {object} required

      Contains the ID of an existing project, or describes a new project to be created by 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.

          Template project

          You can provide either the ID of an existing project to run the template in, or specify a project to be created or updated. You cannot update the region or cluster of a project.

          A new project specification looks like this:

          {
            "project": {
              "spec": {
                "name": "My new project",
                "description": "A new project created by this template",
                "color": "#57637A",
                "region": "europe-west"
              }
            }
          }
          

          If you are using another cloud provider, you can provide clusterId instead of region, where clusterId is the ID of the cluster you want to use.

          To use an existing project you can provide only the project ID:

          {
            "id": "your-project-id"
          }
          

          The project object can contain one of the following:

          • (multiple options: oneOf)

            Details of the project the template will run in.

            • {object}

              Use an existing project

              • id

                string required

                The ID of the project to use.

              OR

            • {object}

              Create a new project

              • spec

                (multiple options: oneOf) required

          If you run a template that creates a project with the same name as an existing project in the account, it will update the project according to the template. If the template specifies a region different to the existing project, the template run will fail.

          If you run a template that specifies (but does not create) a project that doesn't exist in the account, the template run will fail.

          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
          • Resource: specifies a project, 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

          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.

          Argument overrides

          Argument overrides can be used to inject secure values into your template, or override existing argument values. Key-value pairs in the argumentOverrides object will override arguments with the same key in the arguments object.

          Argument overrides are stored securely on Northflank, separately from your template. 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 templates that include argument overrides.

          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": ""
            },
            "spec": {
              "kind": "Workflow",
              "spec": {
                "type": "sequential",
                "steps": [
                  ...
                ]
              }
            },
            "options": {
              "runOnCreation": true,
              "runOnCreationArgumentOverrides": {
                "ARGUMENT_1": "value_1",
                "ARGUMENT_2": "value_2",
                "ARGUMENT_3": "value_3"
              },
              "autorun": false
            }
          }
          

          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.

          Add your ref as a string and it will return a promise, which resolves to the relevant response. 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.

          You can see how references are used in the parallel template example.

          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')}"
                      }
                    }
                  }
                ]
              }
            }
          }
          

          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.

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

          {
            "kind": "workflow",
            "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.

          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
          PipelinePipelineCreates or updates a pipeline
          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 below example creates a deployment service called nginx, deploying the nginx image from Docker Hub . It also publicly exposes port 80 using HTTP.

          {
            "kind": "DeploymentService",
            "spec": {
              "name": "nginx",
              "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.

          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.

          Deployment 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.

          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.

          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.

          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

              {object} required

              The specification for the Addon node.

          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.

          Pipeline

          • {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.

          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.

          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.

            • 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.

            • 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.

            • condition

              string
              one of
              success

          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.

          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.

          Example of a sequential template

          This example demonstrates the deployment of a PostgreSQL addon and a WikiJS image from Docker Hub .

          The template goes through the following steps:

          1. Include the details for the template: apiVersion, name, and description
          2. Create a project for the template to run in, specifying the name, region, description, and color. If a project with this name exists in the region, it will update the resources in the project as given in the template when run. If a project with this name exists in a different region, the template run will fail.
          3. Add a sequential workflow to include the steps to run in the template:
            1. Create a PostgreSQL addon
            2. Create a secret group with the addon connection details and relevant aliases to provide the database connection details to the application
            3. Create a deployment service, pulling the external image from Docker Hub. It has two ports configured, a public HTTP port and a private TCP port to connect to the database.
          An example of a sequential template run in the Northflank application

          When the template runs, it will wait for the previous step in the workflow to complete before executing the next. The database is created first in order to create a secret group with the addon connection details. As the secret group is unrestricted, the deployment created afterwards will then inherit the connection detail secrets with the necessary aliases for the application.

          {
            "apiVersion": "v1",
            "name": "Sequential Payload template",
            "description": "Example of a template with a sequential workflow",
            "project": {
              "spec": {
                "name": "Sequential Payload template",
                "region": "europe-west",
                "color": "#7FD1B9",
                "description": "Project created by an example template with a sequential workflow"
              }
            },
            "spec": {
              "kind": "Workflow",
              "spec": {
                "type": "sequential",
                "steps": [
                  {
                    "kind": "Addon",
                    "spec": {
                      "name": "database",
                      "type": "mongodb",
                      "version": "latest",
                      "billing": {
                        "deploymentPlan": "nf-compute-50",
                        "storageClass": "ssd",
                        "storage": 4096,
                        "replicas": 3
                      },
                      "tlsEnabled": true
                    }
                  },
                  {
                    "kind": "CombinedService",
                    "ref": "payload",
                    "spec": {
                      "name": "payload",
                      "billing": {
                        "deploymentPlan": "nf-compute-50"
                      },
                      "deployment": {
                        "instances": 3,
                        "storage": {
                          "ephemeralStorage": {
                            "storageSize": 1024
                          }
                        }
                      },
                      "ports": [
                        {
                          "name": "p01",
                          "internalPort": 3000,
                          "public": true,
                          "protocol": "HTTP",
                          "disableNfDomain": false
                        }
                      ],
                      "vcsData": {
                        "projectUrl": "https://github.com/northflank-guides/deploy-payload-on-northflank",
                        "projectType": "github",
                        "projectBranch": "master"
                      },
                      "buildSettings": {
                        "dockerfile": {
                          "buildEngine": "kaniko",
                          "dockerFilePath": "/Dockerfile",
                          "dockerWorkDir": "/",
                          "useCache": 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": "${fn.randomSecret(32)}"
                        }
                      },
                      "addonDependencies": [
                        {
                          "addonId": "database",
                          "keys": [
                            {
                              "keyName": "MONGO_SRV",
                              "aliases": [
                                "MONGODB_URI"
                              ]
                            }
                          ]
                        }
                      ]
                    }
                  }
                ]
              }
            }
          }
          

          Example of a parallel template

          This example demonstrates the deployment of a MongoDB addon and the build and deployment of a Payload server .

          The project resources can be initialised simultaneously, so the services and addon are created at the same time. Conditions are then used to check that the database is running and that the build has completed, before creating a secret group and deploying the build. This means that the resources can be created faster, and steps are only executed when they should succeed.

          The template goes through the following steps:

          1. Include the details for the template: apiVersion, name, and description
          2. Create a project for the template to run in, specifying the name, region, description, and color. If a project with this name exists in the region, it will update the resources in the project as given in the template when run. If a project with this name exists in a different region, the template run will fail.
          3. Add a sequential workflow to include the steps to run in the template:
            1. Add a parallel workflow to:
              1. Create a MongoDB addon
              2. Create a deployment service with no instances
              3. Add a sequential workflow to:
                1. Create a build service
                2. Begin a build of the latest commit to the master branch using the build service
            2. After the parallel workflow has executed the template continues running sequentially:
              1. A secret group is created containing the connection details for the addon, the DNS entry for the deployment service, and a random secret
              2. A parallel workflow is added with:
                1. A condition node to check the MongoDB addon has initialised and is running
                2. A condition node to check the build has completed
              3. After both checks are successful the deployment service is updated to deploy the master branch from the build service, and scaled to 1 instance, now inheriting the necessary secrets
          A parallel template run in the Northflank application
          {
            "name": "Parallel Payload template",
            "description": "Example of a template with parallel workflows",
            "project": {
              "spec": {
                "name": "Parallel Payload template",
                "region": "europe-west",
                "color": "#6F2DBD",
                "description": "Project created by an example template with parallel workflows"
              }
            },
            "apiVersion": "v1",
            "spec": {
              "kind": "Workflow",
              "spec": {
                "type": "sequential",
                "steps": [
                  {
                    "kind": "Workflow",
                    "spec": {
                      "type": "parallel",
                      "steps": [
                        {
                          "kind": "Addon",
                          "ref": "payloadDatabase",
                          "spec": {
                            "billing": {
                              "replicas": 1,
                              "storage": 4096,
                              "deploymentPlan": "nf-compute-50",
                              "storageClass": "ssd"
                            },
                            "name": "Payload database",
                            "type": "mongodb",
                            "version": "7-latest",
                            "tlsEnabled": true,
                            "externalAccessEnabled": false,
                            "ipPolicies": [],
                            "pitrEnabled": false
                          }
                        },
                        {
                          "kind": "Workflow",
                          "spec": {
                            "type": "sequential",
                            "steps": [
                              {
                                "kind": "BuildService",
                                "spec": {
                                  "name": "Payload builder",
                                  "billing": {
                                    "deploymentPlan": "nf-compute-100-1"
                                  },
                                  "vcsData": {
                                    "projectUrl": "https://github.com/northflank-guides/deploy-payload-on-northflank",
                                    "projectType": "github"
                                  },
                                  "buildSettings": {
                                    "dockerfile": {
                                      "buildEngine": "kaniko",
                                      "dockerFilePath": "/Dockerfile",
                                      "dockerWorkDir": "/"
                                    }
                                  },
                                  "buildConfiguration": {
                                    "prRestrictions": [
                                      "*"
                                    ],
                                    "branchRestrictions": [
                                      "master"
                                    ]
                                  },
                                  "disabledCI": false,
                                  "buildArguments": {},
                                  "buildFiles": {}
                                },
                                "ref": "payloadBuilder"
                              },
                              {
                                "kind": "Build",
                                "ref": "payloadBuild",
                                "spec": {
                                  "id": "${refs.payloadBuilder.id}",
                                  "type": "service",
                                  "branch": "master",
                                  "buildOverrides": {
                                    "buildArguments": {}
                                  }
                                }
                              }
                            ]
                          }
                        },
                        {
                          "kind": "DeploymentService",
                          "ref": "payloadDeploy",
                          "spec": {
                            "deployment": {
                              "instances": 0,
                              "storage": {
                                "ephemeralStorage": {
                                  "storageSize": 1024
                                }
                              },
                              "docker": {
                                "configType": "default"
                              }
                            },
                            "name": "Payload deployment",
                            "billing": {
                              "deploymentPlan": "nf-compute-50"
                            },
                            "ports": [
                              {
                                "name": "p01",
                                "internalPort": 3000,
                                "public": true,
                                "protocol": "HTTP",
                                "security": {
                                  "credentials": [],
                                  "policies": []
                                },
                                "domains": [],
                                "disableNfDomain": false
                              }
                            ],
                            "runtimeEnvironment": {},
                            "runtimeFiles": {}
                          }
                        }
                      ]
                    }
                  },
                  {
                    "kind": "SecretGroup",
                    "spec": {
                      "priority": 10,
                      "name": "payload-secrets",
                      "secretType": "environment-arguments",
                      "addonDependencies": [
                        {
                          "addonId": "${refs.payloadDatabase.id}",
                          "keys": [
                            {
                              "keyName": "MONGO_SRV",
                              "aliases": [
                                "MONGODB_URI"
                              ]
                            }
                          ]
                        }
                      ],
                      "secrets": {
                        "variables": {
                          "PAYLOAD_SECRET": "${fn.randomSecret(32)}",
                          "PAYLOAD_PUBLIC_BASE_DNS": "https://${refs.payloadDeploy.ports.0.dns}"
                        }
                      },
                      "restrictions": {
                        "restricted": false,
                        "nfObjects": [],
                        "tags": []
                      }
                    }
                  },
                  {
                    "kind": "Workflow",
                    "spec": {
                      "type": "parallel",
                      "steps": [
                        {
                          "kind": "Condition",
                          "spec": {
                            "kind": "Build",
                            "spec": {
                              "type": "success",
                              "data": {
                                "buildId": "${refs.payloadBuild.id}"
                              }
                            }
                          }
                        },
                        {
                          "kind": "Condition",
                          "spec": {
                            "kind": "Addon",
                            "spec": {
                              "type": "running",
                              "data": {
                                "addonId": "${refs.payloadDatabase.id}"
                              }
                            }
                          }
                        }
                      ]
                    }
                  },
                  {
                    "kind": "DeploymentService",
                    "spec": {
                      "deployment": {
                        "instances": 1,
                        "internal": {
                          "buildId": "${refs.payloadBuild.id}"
                        },
                        "docker": {
                          "configType": "default"
                        }
                      },
                      "name": "Payload deployment",
                      "billing": {
                        "deploymentPlan": "nf-compute-50"
                      },
                      "ports": [],
                      "runtimeEnvironment": {},
                      "runtimeFiles": {}
                    }
                  }
                ]
              }
            }
          }
          

          © 2024 Northflank Ltd. All rights reserved.