Improving The CI/CD Flow For Your Application — Smashing Magazine

Improving The CI/CD Flow For Your Application

About The Author

Tom Hastjarjanto is a software engineer from the Netherlands. He works as a consulting software engineer for Sytac,io. He has worked primarily on …
More about
Tom ↬

Email Newsletter

Quick summary ↬
Looking for ways to create a smooth CI/CD flow for your software? In this article, Tom Hastjarjanto shares a quick list of useful concepts that can be combined with GitHub Actions and NPM packages. To fully benefit from the setup and the release with maximum confidence, it is highly recommended to have a robust test suite that runs on integration.

Big tech companies have the ability to make thousands of releases per day. Already back in 2011, Amazon released new software once every 11.6 seconds. These companies typically have entire teams working on improving the delivery speed of their product teams. Luckily, many of the best practices used at these tech companies are well documented and have open-source tools available for every team to achieve the same delivery performance as big tech companies.

In this article, we will go through a few concepts which can be combined to create a modern CI/CD flow for your software. We will use GitHub Actions and NPM packages as a base, but the tools and concepts can be applied to any language. I’ve used them to successfully release Python packages and Docker containers.

GitHub Flow

GitHub Flow is a lightweight branching model that is suggested by GitHub. For most companies and teams this is more than sufficient, and it’s very suitable for modularized code and microservices. Teams that have decided on Gitflow, often do not run in the edge cases or situations for which the complete flow offers solutions (e.g. hotfixes, multiple active releases of software).

The rules are simple:

This strategy works well when your team adopts short-living branches and keeps the scope of changes small. If you choose to work on larger features and keep branches around for a longer period, you will have a hard time periodically resolving merge conflicts.

By creating releases often, you reduce the scope of the changes, and therefore the risk of issues after a new deployment. This will also reduce the necessity of creating hotfix releases since those can be handled in the regular development flow. Since the scope of changes for releases are small, and your pace of delivery is fast, there is often no need to have separate release branches around for any bug fixes.

Semantic Version

Semantic versioning is a version numbering strategy to communicate the scope of the change of your new release.

The release version is specified in the following form: vX.Y.Z

By checking the version number, others can quickly estimate the impact of the new release, and decide whether they should automatically update to your new version or schedule some time to handle the breaking changes.

Conventional Commits

Conventional commits are, as the name implies, a convention on how to structure your commit messages. The pattern of this convention looks like this:

A few practical examples:

The specification allows for some flexibility towards the types, but the most important ones are the following:

More after jump! Continue reading below ↓ with useful tips on front-end, design & UX. Subscribe and get “Smart Interface Design Checklists” — a free PDF deck with 150+ questions to ask yourself when designing and building almost anything.


Once a week. Useful tips on front-end & UX. Trusted by 190.000 friendly folks.

Feature Panel

Meet with useful tips on front-end, design & UX. Subscribe and get “Smart Interface Design Checklists” — a free PDF deck with 150+ questions to ask yourself when designing and building almost anything.


Once a week. Useful tips on front-end & UX. Trusted by 190.000 friendly folks.

Standard Version

What is the point of conventional commits, you may ask. In general, using conventions allows you to build tooling and automation. That is also the case for conventional commits. For example, you can automatically generate release notes and bump your package version. Standard Version is a tool that automatically does that for you.

The Standard version parses your Git log for the following purpose:

To install the Standard Version, you can use NPM:

You can then add it to your package.json as a script:

Or, alternatively, use npx:

When you want to create a release, you can simply run npm run release, and Standard Version will take of the rest. Typically, you will configure your CI/CD pipeline to perform these tasks for you.

If you want to move fast, you can set up your pipeline to create a release every time a pull request is merged in your codebase. In this case, you have to be cautious that your pipeline doesn’t create an infinite build loop, since the tool will commit and push changes to itself. In GitHub Actions, you can include a tag [skip ci] in your commit messages in order to tell GitHub to not trigger a CI build for a certain commit. You can configure a Standard version to include the [skip ci] tag in its configuration in package.json:

GitHub Actions

If you use GitHub, you can use the integrated work automation feature called GitHub Actions. GitHub Actions can be used as your CI/CD service by including a YAML configuration file in a .github/workflows directory in the root of your repository.

For example, you can create a file .github/workflows/learn-github-actions.yml with the following content:

GitHub Actions can be configured to allow itself to commit and push back changes to your repository. To do so, you only need to run git config in your workflow:

Putting It All Together

Combining all of these concepts together will result in a highly automated release flow for your repository. The tooling configuration consists primarily of two sources:

This is how the package.json file looks like (including [skip ci] configuration):

And this is the GitHub Actions workflow that runs on a push to main:

This npm run release will do the following:

git push --follow-tags origin main will finalize the release:

Note: A full example is available in my example repository.

We have explored a couple of concepts that — when combined — can result in an efficient automated setup for your release procedure. With this setup, you will be able to release multiple times per hour with a fully documented trace managed by Git. To fully benefit from the setup and the release with maximum confidence, it is highly recommended to have a robust test suite that runs on integration.

If releasing on each merge is a step too far, you can adapt the setup to be performed manually.

This content was originally published here.