# The savior amidst the chaos of dependency updates - Dependabot

<figure><img src="https://1213438767-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4DXEoZIzUdpt18CW2qTD%2Fuploads%2FzXjtfpnPjXaN7gAZDm9L%2Fexilewatch.webp?alt=media&#x26;token=74fc8000-b114-47be-bc13-cda9b75cd22f" alt="" width="256"><figcaption><p>exile.watch logo</p></figcaption></figure>

I briefly touched on Dependabot in [this section](https://engineering.exile.watch/exile.watch-architecture#with-great-modularity-comes-great-responsibility), but now it's time to dive deeper into the topic.

***

So, you have a list of [dependencies](https://docs.npmjs.com/specifying-dependencies-and-devdependencies-in-a-package-json-file). Sometimes it's short, sometimes it's a mile long.&#x20;

But the big question is, how do you keep those dependencies up-to-date?

[`npm audit fix`](https://docs.npmjs.com/cli/v9/commands/npm-audit)?&#x20;

Sure, that's one approach, reacting to warnings that pop up post-install.&#x20;

But this mainly applies to security updates.&#x20;

What about regular dependency updates, like bumping from a patch version to a minor version, or from a minor version to a major version, without security concerns?

## Enter Dependabot

[Dependabot](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/about-dependabot-version-updates) is GitHub's solution for automated dependency updates, covering a wide range of programming languages including Ruby, JavaScript, Python, [and many more](https://github.com/dependabot/dependabot-core).

## Enabling the budget [Skynet](https://en.wikipedia.org/wiki/Skynet_\(Terminator\))

All it takes is adding a [`dependabot.yml`](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file) config file to your `.github` repo directory.&#x20;

Here's what that might look like:

<pre class="language-yaml"><code class="lang-yaml"><strong># {root}/.github/dependabot.yml
</strong><strong>version: 2
</strong>updates:
- package-ecosystem: "npm"
  directory: "/"
  schedule:
    interval: "weekly"
</code></pre>

Pretty straightforward, right?

***

Now, you might wonder: "Okay, automated pull requests sound great, but what if we have tons of dependencies? Will it flood our repo with individual pull requests for each one?"

Yes, that's exactly what would happen. And at [exile.watch](https://exile.watch/), with our multitude of dependencies spread across projects, that could easily become overwhelming.

So, am I suggesting that every project gets bombarded with a barrage of pull requests on a weekly (or whatever interval you set) basis for every single dependency update?

[By default, yes, Dependabot opens a separate pull request for each dependency update](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#groups).&#x20;

But here's the game-changer:

## Group updates &#x20;

[Group updates](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#groups) are a lifesaver, especially for those managing extensive dependency lists.&#x20;

This [relatively new](https://github.blog/changelog/2023-08-10-group-dependabot-version-updates-by-development-or-production-dependencies/) feature was long requested and for good reason.

It allows you to group sets of dependencies (by package manager) so that Dependabot can open a single pull request to update multiple dependencies simultaneously.

{% hint style="info" %}
Even with grouped updates, if there's a security concern with one of the packages, [Dependabot will still prioritize a separate pull request](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#groups) to address the vulnerability promptly, ensuring you're always informed of potential risks.
{% endhint %}

Here's an example `dependabot.yml` that [exile.watch](https://exile.watch/) uses:

```yaml
# {root}/.github/dependabot.yml
version: 2
registries:
  github:
    type: npm-registry
    url: https://npm.pkg.github.com
    token: ${{ secrets.GH_TOKEN }}
updates:
  - package-ecosystem: "npm"
    directory: "/"
    registries: [github]
    schedule:
      interval: "weekly"
      day: "saturday"
      time: "10:35"
      timezone: "Europe/Warsaw"
    groups:
      exile-watch-build-tools:
        patterns:
          - "@exile-watch/biome-config"
          - "@exile-watch/conventional-changelog-config"
          - "@exile-watch/lefthook-config"
          - "@exile-watch/postcss-config"
          - "@exile-watch/rollup-config"
          - "@exile-watch/typescript-config"
      exile-watch-design-system:
        patterns:
          - "@exile-watch/writ-icons"
          - "@exile-watch/writ-react"
      exile-watch-data:
        patterns:
          - "@exile-watch/encounter-data"
```

{% hint style="info" %}
You might notice the `registries` field:&#x20;

```yaml
registries:
  github:
    type: npm-registry
    url: https://npm.pkg.github.com
    token: ${{ secrets.GH_TOKEN }}
```

By default, when using the npm registry, there's no need to specify the registry.&#x20;

However, [since exile.watch has chosen to host packages on GitHub's NPM registry](https://engineering.exile.watch/march-2024/lerna-the-hidden-powerhouse-of-exile.watch/3.-module-registry-a-place-where-packages-get-to-chill), we needed to include this field.
{% endhint %}

In the case of the [crucible](https://docs.exile.watch/projects/crucible) project, I've opted for grouping all internal dependencies. Meanwhile, for the [splinters](https://docs.exile.watch/projects/splinters) project, the strategy is to group updates by config dependency:

```yaml
# {root}/.github/dependabot.yml
version: 2
registries:
  github:
    type: npm-registry
    url: https://npm.pkg.github.com
    token: ${{ secrets.GH_TOKEN }}
updates:
  - package-ecosystem: "npm"
    directory: "/"
    registries: [github]
    schedule:
      interval: "weekly"
      day: "saturday"
      time: "10:35"
      timezone: "Europe/Warsaw"
    groups:
      exile-watch:
        patterns:
          - "@exile-watch*"
      rollup-config-deps:
        patterns:
          - "@rollup*"
      lefthook-config-deps:
        patterns:
          - "@commitlint*"
          - "commitizen"
          - "lefthook"
          - "cz-conventional-changelog"
      unit-testing-config-deps:
        patterns:
          - "@testing-library*"
          - "vite-tsconfig-paths"
          - "vitest"
```

And here's the result—[grouped pull requests in action](https://github.com/exile-watch/crucible/pull/9):

<figure><img src="https://1213438767-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4DXEoZIzUdpt18CW2qTD%2Fuploads%2Ff0t8QQCi7LK5upRxmbjo%2Fimage.png?alt=media&#x26;token=8cd7e645-952c-488a-9d89-ab4669382301" alt=""><figcaption><p>List of group pull requests opened by Dependabot</p></figcaption></figure>

***

With this approach, managing our dependencies suddenly feels like a walk in the park, and the once daunting architecture, brimming with countless dependencies, doesn't seem so scary anymore :).

***

Author: [Sebastian Krzyżanowski](https://github.com/sbsrnt)\
About *exile.watch*: <https://docs.exile.watch/>\
Github: <https://github.com/exile-watch>\
\
Visit <https://exile.watch/> to experience it first hand
