Keeping dependencies up to date is an important, yet oftentimes overlooked aspect of development. As developers, we like to focus on exciting features in our projects, instead of manually updating an ever-expanding list of dependencies. Thankfully, some tools can help us with automating this tedious task. One of these tools is Dependabot. Let’s have a look at how we can make security a first-class citizen in our projects.
Disclaimer: This guide is primarily aimed at projects hosted on GitHub. General concepts can be reused with other solutions, but specific implementation will only work for GitHub projects.
WHY DO WE UPDATE DEPENDENCIES?
Generally, we want to update our dependencies whenever there is a need for it. This boils down to two primary reasons:
1. There is a bug that gets fixed by a newer version.
2. We need to use a feature introduced in a newer version.
In my personal experience, automating bug fixes and security updates leads to a more resilient codebase. However, not all versions should be immediately auto-merged, especially not on production.
DEPENDABOT TO THE RESCUE
There are many tools out there that help with auto-updating dependencies, but my personal favorite is Dependabot mostly due to its ease of use and being the de-facto official GitHub dependency management since they acquired it back in May 2019 and made it free.
To start using Dependabot, go to The Dependabot Dashboard and Install Dependabot to your GitHub account. You can now select which repositories you want to add. However, this does not yet enable Dependabot on projects, so I like to select “All repositories,” which includes all current and future repositories—but you can hand-pick each repository manually.
Go ahead and “Select repos to add.” After selecting and adding a repository, Dependabot starts checking your dependencies in the dependency list and creates Pull Requests for each dependency that is out of date.
However, this is not the automated solution I promised you in the beginning. On top of that, this solution also requires manually configuring every repository in the Dependabot Dashboard, which doesn’t help with transparency in the project at all. So, let’s take a look at a better way.
AUTOMATION & CONFIGURATION
To allow Dependabot to auto-merge Pull Requests, we need to grant it elevated permissions, which can be done from Account Settings in the Dashboard by checking the “Allow auto-merging to be enabled on projects” option.
Dependabot waits until all your status checks pass in your Pull Request. As such, having a well set up CI solution on your project gives you confidence to auto-merge these updates without worrying about publishing a broken build into production.
As a strong proponent of Infrastructure as Code, I recommend keeping your Dependabot configurations as part of your codebase. Not only because Dependabot can detect this and configure itself accordingly without us needing to fiddle with the Dashboard (given that we have All repositories enabled), but also because it increases transparency for all members of the team working on the codebase and provides versioning of the configuration.
All we need to do now is create a .dependabot/config.yml file in the root of our project and fill it according to Dependabot Config Docs. Once the pushed configuration file is valid (which you can check in the Validator), the Dependabot will start checking your dependencies.
DEPENDENCY SETUP FOR PRODUCTION
Next up is my dependency setup for projects in production. (The example uses JavaScript, but you can choose whichever package manager you need.)
I make sure that my dependencies are kept up-to-date with security patches directly in the production branch. The Dependabot also creates a weekly update of dependencies into the development branch for the team to review, and it auto-merges development dependencies.
version: 1
update_configs:
# Creates security updates as soon as they become available and auto-merges them into the "production" branch.
- package_manager: "javascript"
directory: "/"
update_schedule: "live"
target_branch: "production"
allowed_updates:
- match:
dependency_type: "production"
update_type: "security"
automerged_updates:
- match:
dependency_type: "production"
update_type: "security:patch"
version_requirement_updates: "increase_versions"
# Creates weekly Pull Requests with dependency updates and auto-merges devDependency updates.
- package_manager: "javascript"
directory: "/"
update_schedule: "weekly"
target_branch: "dev"
allowed_updates:
- match:
dependency_type: "production"
update_type: "all"
- match:
dependency_type: "development"
update_type: "all"
automerged_updates:
- match:
dependency_type: "development"
update_type: "all"
version_requirement_updates: "increase_versions"
DEPENDENCY SETUP FOR TEMPLATES
Templates, bootstrapping projects and generators need a slightly different setup. As there is rarely any business logic that could break, we don’t have to care that much about potential breaking changes. But that doesn’t mean we can skimp on CI setup.
On the other hand, here we want to keep all the dependencies as recent as possible; after all, we don’t want to create a fresh project and already have outdated dependencies.
This is why I prefer my templates living their own life, without my constant intervention, so that Dependabot auto-merges everything as long as my CI checks pass.
version: 1
update_configs:
- package_manager: "javascript"
directory: "/"
update_schedule: "daily"
automerged_updates:
- match:
dependency_type: "all"
update_type: "all"
version_requirement_updates: "increase_versions"
SUMMARY
Dependabot is an amazing tool for keeping dependencies up-to-date, but it requires a proper configuration—otherwise, you can get a ton of emails and run out of build minutes on your project quickly if your CI runs on every commit in Pull Requests.
Make sure you read Dependabot Docs carefully and play around with it until it is just right.
Happy hacking.