What Makes a CI/CD Pipeline Great?

Whether you're shipping a mobile app or deploying a backend service, your Continuous Integration and Continuous Deployment (CI/CD) pipeline is the gatekeeper of quality and security. A good pipeline can catch bugs in minutes, but a great one helps prevent incidents before they reach production. Here, I'll review the essentials for a CI/CD pipeline, and in a future post I will highlight where security can help go above and beyond.

CI/CD Essentials

First, the basics. CI/CD is all about giving fast feedback to developers, enabling more frequent deployments to production. To facilitate this, a collection of basic CI tasks can be especially helpful.

Dependency Install

As part of CI, you should be installing dependencies (preferably from a lock file) to validate the correct configuration. Because dependencies are often external to the codebase, it is likely necessary to install these dependencies for the other CI tasks.

Compilation

If your language supports compilation (like Java, Go, or Rust), it is one of the most straightforward tests available. Running compilation tasks as part of CI will ensure the code builds cleanly.

Unit Testing

Every CI pipeline needs to have unit testing to give quick feedback to your developers and detect any regressions in their code changes. Unit tests aren't perfect – they'll only catch the problems you're looking for – but they can be a great tool for establishing a baseline quality.

Linting

A lint task in the CI pipeline will be useful if there are code style standards to maintain. Not every application will require this, but it is a great addition to catch when someone is adding tabs to a codebase that uses spaces.

Versioning

Each build needs a unique version to support traceability, debugging and rollback. If appropriate for the language, Semantic Versioning is a great way to manage versions. The CI system should generate one automatically if developers do not set a version explicitly.

Packaging

A packaging step gives developers an opportunity to move files in preparation for publishing the build artifact. This simple step ensures the artifact has only the essentials included.

Publishing

The culmination of the CI pipeline results in a build artifact being published. These days, this is typically a container image pushed to a registry, but it could also be a JAR file published to a remote repository, or even just a collection of files ready to be moved to a server.

Deploying

There are a multitude of different options for deployments, but I like to deploy feature branches to dedicated test environments and deploy the main branch to a persistent non-production environment followed by production. This allows developers to test their changes in an isolated environment before they merge, plus protects the production environment from any changes that do not pass tests in preprod.

Deployment Verification

Finally, once the deployment is complete it is useful to run some tests to validate the change. These could include end-to-end or smoke tests, but should run quickly to determine if there are any issues with the application. This could be as simple as using curl to validate the deployment, or running Cypress for more advanced tests.

With these building blocks in place, your CI/CD pipeline becomes a reliable foundation for shipping software. Next, we’ll look at how to level up — with security scans, image signatures, and policy enforcement.