Keeping dependencies in your GitHub projects up-to-date with Dependabot
Published: 2024-01-06 18:44:59

Nowadays software is rarely being written from scratch using only vanilla language features. Applications usually consist of numerous frameworks, libraries and utilities provided by 3rd parties. The true mastery is to pick the right tooling and glue the features together in the best way to achieve the goals.

The necessity of managing all the external dependencies lead to specialized tools called “package managers” that help you dealing with them. There are different managers for different languages. We have Maven or Gradle for Java, npm, yarn or pnpm for JavaScript, pip for Python, NuGet for .NET, the list goes on.

They made declaring and getting dependencies easy. But this is just the first part of the story. You also need to maintain and update them. Otherwise, your once brand new shiny application eventually becomes rusty, obsolete and even dangerous for its users.

Keeping your dependencies up-to-date is important for reasons like:
- ensuring compatibility with the latest technology
- maintaining security by patching vulnerabilities
- enhancing overall performance by leveraging improvements in dependent packages

Like most things in software development, you can call automated tools for help to avoid checking for new available versions manually. With the right setup it can change from an annoying chore to a very simple and quick task.

Here I will talk about Dependabot, an option for GitHub hosted projects (but hey, [an integration for GitLab](https://gitlab.com/dependabot-gitlab/dependabot) exists as well). I will show you how to set it up in just a few easy steps embracing the latest features for the best developer experience.

## Getting started with Dependabot

Since I use Dependabot mostly for my JavaScript ([Nuxt](https://nuxt.com/)) projects and I tend to prefer good ol’ `npm` over other package managers, I will be showing it for this setup. However, you have many more options. You can see all the supported variants [here](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem). The process is basically the same for all of them.

Enabling Dependabot for GitHub is fairly easy. You only need to add `/.github/dependabot.yml` file into the root of your project. This file contains configuration options for automated runs. Here you can see an example of setting version update to run _every first day of the month at 01:00 a.m._ in npm-based repository:

```yaml
# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "monthly"
      time: "01:00"
    commit-message:
      prefix: "npm"
```

Parameter `directory` locates your `package.json` (or respective file with dependency definitions). In this case we assume that it is preset directly in the root. But for example, in a project at my work we have the JS application wrapped inside a Docker container, so the value would have to be `/app`. Or you could have a monorepo with multiple sub-projects. Then you need to set Dependabot separately for each. Here ïs [an example](https://github.com/AloisSeckar/demos-nuxt/blob/main/.github/dependabot.yml).

Dependabot can run on a `daily`, `weekly` or `monthly` basis. Use `schedule – interval` option to set the desired value. I started running it weekly, but after a while I found it tedious and unnecessary both from the perspective of my projects and the number of new versions being released. Updating dependencies once per month seems reasonable enough. The exact `time` is up to you. It may align with your habits (I like to have it done early in the morning, so I can wake up and see the result) or with the project release cycle. When using `interval: “weekly”`, you can add `day` option to specify which day of the week it should be. Sadly, you cannot pick certain day for `monthly` frequency – it will always be the 1st day of each month.

The full configuration reference can be found [here](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file).

## Yes, but…

This worked quite well, but there was a problem – it created new PR for **EACH** updated dependency. You could have easily ended up with like 10 to deal with. To make things worse, each PR tampered with `package-lock.json` (or corresponding lockfile depending on the target package manager). With more changes coming from different PRs this almost always caused merge conflicts. You basically had to ignore them and re-run `npm install` after all PRs were merged.

To address inefficiency caused by separate PRs, [a workflow was designed](https://github.com/hrvey/combine-prs-workflow) to join them automatically into one big PR. However, it was unable to deal with lockfile conflicts. PRs that caused conflict in the `Combine PRs` job, were omitted and you had to add them manually anyway. It spared some time, but the developer experience was still far from being perfect.

## Salvation

Fortunately, a breakthrough happened last summer. In August 2023, [GitHub has announced Dependabot’s update](https://github.blog/2023-08-24-a-faster-way-to-manage-version-updates-with-dependabot/) that finally allows version update PRs to be natively joined.

There are several options allows you to fine-grain your version management and you can learn about them [in the docs](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#groups). But for the sake of simplicity let’s just cover the basic usecase: _“I want to update all my npm deps to latest available versions in one simple step.”_

All you have to do is to now is to add `groups` option into your `/.github/dependabot.yml` like this:

```yaml
# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "monthly"
      time: "01:00"
    commit-message:
      prefix: "npm"
    groups:
      all:
        patterns:
          - "*"
```

To understand what’s going on - `all` is just a custom placeholder to identify the group. It can be whatever you like (and is allowed inside `yaml` files). Through `patterns` you can specify dependency names to be included. Since we want all the dependencies, we use `"*"` wildcard to match everything.

**And that’s it!**

Next time the automated action runs, it prepares just one pull-request. It is also well documented. You can easily see what’s new with links to respective projects:

![Info about updated versions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ym6n2wd60y4ge23lp504.png)

You can even see the release notes, changelogs and commits, if available from the source projects:

![Detailed info about an update](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7jnf6whsquu3lvmqp5zf.png)

Switching to “Files changed” tabs you can revise changes made in `package.json`:

![Changes in package.json](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b0krdcuaqm8inyqi2hf0.png)

Dependabot also handles the lockfile. Unlike before when there were a lot of conflicts to solve, Dependabot now does all the hard job and leaves you just with the final outcome.

Therefore, all you need to do now is to review the changes and approve the pull request. And you’re done until the next time. 

This step can probably be automated too, but I prefer checking what is new and see if it didn’t break anything in my apps. Because sadly this happens from time to time. Sometimes you have to change something in your source code, sometimes you are even forced to reverse version of some particular package until their authors deal with the regression. But having your codebase up-to-date most of the time is worth it.

## Security alerts

It is also worth mentioning that if allowed, Dependabot also monitors severe security vulnerabilities and it may produce security update anytime in between the scheduled period.

![Dependabot security alert](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0wdkdq2ro84kswyfod6b.png)

Those alerts usually result in only small changes in the lockfile. Dependabot prepares everything, provides an explanation, sends a notification and only leaves you with accepting its PR. Needless to say you should address those alerts as soon as possible to keep your apps safer.

## Conclusion

That concludes this tutorial. You have seen how to use Dependabot to semi-automate your dependency management. If you have questions, doubts or alternative setups, feel free to share them with us in the comments below.

I hope this helps you create and maintain awesome applications and I wish you the best of luck on your never-ending software development journey.

**P.S.** While this being a powerful and handy tool itself, it is only a part of Dependabot’s capabilities. If you are interested, you’ll find more about them in the [GitHub docs](https://docs.github.com/en/code-security/dependabot).