---
sidebar_label: CI-CD pipelines
toc_max_heading_level: 3
doc_id: 9ece1dd0-59f7-4645-833d-35fa9292db17
description: >-
  Guide for integrating CI/CD pipelines with nullplatform to automate builds,
  releases, and deployments.
keywords:
  - CI/CD
  - continuous integration
  - continuous delivery
  - continuous deployment
  - branch patterns
  - nullplatform
  - automation
---

# CI-CD pipelines

## What is CI/CD?

**Continuous Integration and Continuous Delivery (CI/CD)** automates, optimizes, and secures the development lifecycle,
leading to faster, more reliable releases.

CI/CD is typically structured as a pipeline with these key stages:

- **Continuous Integration (CI):** Developers frequently merge changes into a shared branch, triggering automated builds
   and tests to catch conflicts early.
- **Continuous Delivery (CD):** Code that passes tests is packaged and prepared for deployment, ensuring it is always
  deployment-ready. On top of this, you can have **continuous deployment** where the software is automatically deployed 
  to production or to your testing environment, depending on your configuration.


## Configuring nullplatform in your CI/CD

To leverage nullplatform in your development lifecycle, you need to configure your CI/CD pipeline to notify nullplatform
about new builds, releases, and assets.

With the [nullplatform's CLI](/docs/cli), you can seamlessly integrate with any CI/CD tool, including GitHub Actions,
GitLab, Jenkins, and Azure Pipelines.

### Create or import the application

Before setting up your CI/CD pipeline, you need to [create or import your application](/docs/applications/creating-new-application.md)
in nullplatform. This is required because communicating with nullplatform requires credentials, which are injected into
your CI/CD pipeline when the application is created or imported.

### Create builds and assets

This is the first touchpoint with nullplatform in the development lifecycle. It starts by notifying that your
application is being built and ends with the production of a set of assets, which will eventually be delivered to
runtime environments.

Here's an example of how we'd modify a CI/CD workflow to achieve this:

```yaml
############################################################################
### Example of how to modify a workflow that builds a Docker image
############################################################################

# Install the np cli binary that will take care of communication with nullplatform API
- name: Install nullplatform's CLI
  run: curl https://cli.nullplatform.com/install.sh | sh

  # Check out your code
- name: Check out the code
  uses: actions/checkout@v4

  # Create the build with a 'creating' status, 
  # This will be automatically reflected on nullplatform's UI.
- name: Create build on nullplatform
  run: np build start

  # Build and test
- name: Build and test
  run: docker build -t main .

  # Add the asset to the build
- name: Add the asset to the build
  run: np asset push --type docker-image --source main

  # Update the build to its final status
- name: Set the build as successful or failed
  if: ${{ always() }}
  run: np build update --status ${{ contains(fromJSON('["failure", "cancelled"]'), job.status) && 'failed' || 'successful' }}  
```

Here's how the workflow works:

1. **Install the CLI**: This utility handles communication with nullplatform's API.
2. **Start a build:** We used `np build start` to notify nullplatform that a build has begun. This is reflected in the
   **Builds** section of the UI, where your build will appear with a `Creating` status.
3. **Upload assets:** We used `np asset push` to (a) upload the assets (e.g., Docker images, Lambda functions) to the
    designated repository, and (b) add the asset metadata to the build.

:::note
The image goes directly into your image repository. It is not proxied by nullplatform's servers.
:::

4. **Update build status:** We used `np build update` to inform nullplatform whether the build succeeded or failed.

#### How do I handle failed builds?

As shown in the example above, you can use `np build update --status failed` to notify nullplatform of a failed build.
Nullplatform will mark the build as failed and prevent it from being deployed.

<!-- #### How does the CLI authenticate against my asset repository?

Notice that the workflow above never logs into the registry. `np asset push` takes the credentials from the asset
repository provider configured in nullplatform: a Docker registry's username and password, or, for ECR, an IAM role or
access key pair. Your pipeline doesn't have to hold registry secrets. See
[Asset push authentication](/docs/applications/ci-cd/asset-push-authentication) for how it works, how to set up each
CI tool, and how to log in from the pipeline yourself with `--no-login`. -->

## Continuous Deployment (CD)

To implement CD on nullplatform, go to your application's **Scopes** settings, enable **Continuous Deployment**, and
list the branches that should trigger an automatic release into that scope.

Example CD configuration:

- **Branch**: `main`
- **Scope**: `staging`
- **Action**: Automatically deploy builds from `main` to the staging scope.

#### What happens when I configure CD?

When you configure CD, nullplatform automatically handles the following:

1. **Generates a new release**, automatically incrementing the semantic version based on the latest release.
2. **Executes the deployment** on the scopes marked for CD. Note that this will be an "all-in" deployment, meaning
   there will be no traffic-switching phase.

### Matching branches with regular expressions

The **Branches** field accepts regular expressions, not just literal branch names. Each entry you add is a pattern, and
a successful build triggers a deployment when its branch matches at least one of them. This way a single scope can pick
up a whole family of branches without you listing them one by one.

Three rules govern how patterns are evaluated:

- Patterns must match the **entire** branch name. `feature` won't match `feature/login`, but `feature/.*` will.
- Matching is **case-insensitive**, so `Main` and `main` are treated the same.
- A scope can hold as many patterns as you need. One match is enough to trigger the deployment.

Here are some common patterns:

| Pattern | Matches | Doesn't match |
| --- | --- | --- |
| `main` | `main` | `main-fix`, `feature/main` |
| `release/.*` | `release/1.2.0`, `release/hotfix` | `release`, `releases/1.2.0` |
| `feature/.*` | `feature/login`, `feature/team/login` | `feat/login` |
| `main\|develop` | `main`, `develop` | `development` |
| `hotfix-\d+` | `hotfix-42` | `hotfix-abc` |
| `.*` | Every branch | Nothing |

A plain branch name is already a valid pattern: `main` is a regular expression that matches only itself. You only need
the extra syntax when a scope should cover more than one branch.

:::caution

If a pattern isn't a valid regular expression, nullplatform can't evaluate it and the scope is skipped, so no
deployment is triggered. Double-check special characters such as `[`, `(`, and `\` when writing patterns by hand.

:::


## Adding catalog metadata to the CI/CD process

You can enrich your builds with **catalog metadata** to enforce policies or improve decision-making. For example, you can store test coverage data and prevent deployments if coverage is too low:


```yaml
np metadata create --entity build --data '{"linter": { "code_smells": $CODE_SMELLS }, "coverage": { "percentage": $COVERAGE } }'
```
By leveraging metadata, you can enforce quality control before pushing builds to production.

For more information, see our [Entity catalog documentation](/docs/catalog/getting-started.md). 

## Adding multiple assets to a build

Nullplatform supports builds that produce multiple assets. For example, you can build both a Docker image and a Lambda
function in the same workflow.

Example multi-asset workflow:

```yaml
- name: Start Build
  run: np build start

- name: Build Docker Image
  run: np asset push --type docker-image --source my-app

- name: Build Lambda Function
  run: np asset push --type lambda --zip my-lambda.zip

- name: Update Build Status
  run: np build update --status success
```

## Best practices

To streamline your CI/CD experience in nullplatform, consider the following best practices:

- #### Use templates

   We provide [pre-built templates](/docs/api/technology-template-list) for common technologies. These templates include
   ready-to-use CI/CD workflows, so you don't have to start from scratch.

- #### Leverage catalog metadata
  
   Use metadata to enforce quality and security policies. For example:

   - Require a minimum code coverage (e.g., 80%) for production deployments.
   - Block deployments if critical vulnerabilities are detected.
  
  See our [Catalog entity docs](/docs/catalog/getting-started) for more info. 

- #### Keep pipelines simple

   Once your application is on nullplatform, your pipelines don’t need to handle low-level infrastructure interactions for deployment purposes. Simplify your pipelines by focusing only on building and testing code.

- #### Choose a branching strategy
  
  Pick a branching strategy that works for your team. For example:

  - Git flow: Use `main` for production and `develop` for staging.
  - Trunk-based development: Use a single branch (`main`) for all deployments.


## What's next?

Check out our [full CI/CD workflow examples](/docs/applications/ci-cd/full-ci-cd-examples) using different CI tools integrated with nullplatform.
