---
title: 'Announcing importmap-update: automated dependency updates for importmap-rails'
teaser: Dependabot keeps your gems current, but it doesn't know about the JavaScript
  packages pinned in your Rails importmap. We're releasing a GitHub Action that opens
  pull requests for the ones that are outdated or vulnerable.
tags: open source,javascript,rails,github actions,development
author: Neil Carvalho
published_on: 2026-09-09
---

Dependabot helps you keep your gems updated, and it also supports other
package managers such as NPM. However, it doesn't know anything about
the JavaScript packages in a Rails app that uses [importmap-rails], and the
[feature request][dependabot-6675] for that has been open since February 2023.

That means that when you dropped Node from your Rails app, you also dropped the
tooling that would tell you a pinned package had fallen behind or picked up a
published advisory.

[importmap-update] is a GitHub Action that closes that gap. It runs
`bin/importmap outdated` and `bin/importmap audit`, opens pull requests for what
it finds, and keeps those pull requests in sync on every run after that.

## Why importmaps get left behind

An importmap-rails app records its JavaScript dependencies in
`config/importmap.rb`. Running `bin/importmap pin react` resolves the package
through a CDN like JSPM, downloads it into `vendor/javascript`, and writes a
one-line pin with the version in a trailing comment:

```ruby
pin "react" # @19.1.0
```

Your own asset pipeline serves the vendored copy from there. What lands in
source control is that comment and the JavaScript file itself, so there's no
`package.json` and no lockfile for Dependabot to read. The information it would
want is available, just somewhere else: `bin/importmap outdated` compares your
pins against the npm registry, and `bin/importmap audit` checks them for known
advisories.

Half of that is already wired up for you. Since Rails 7.2, new apps are
generated with a `.github/workflows/ci.yml` that includes a `scan_js` job:

```yaml
- name: Scan for security vulnerabilities in JavaScript dependencies
  run: bin/importmap audit
```

A published advisory against one of your pins will fail the build, which is the
part you'd want to hear about first. It still stops at telling you, though.
Someone has to look up the fixed version and pin it by hand.

Nothing runs `bin/importmap outdated`. Ordinary version drift stays invisible
until it turns into an advisory, and by then you're upgrading in a hurry.

## Getting started

Allow GitHub Actions to create pull requests in your repository settings
(Actions > General > Workflow permissions), then add a workflow:

```yaml
# .github/workflows/importmap-updates.yml
name: Importmap updates
on:
  schedule:
    - cron: "0 9 * * 1"   # Mondays 09:00 UTC
  workflow_dispatch:

permissions:
  contents: write
  pull-requests: write

jobs:
  update:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true

      - uses: thoughtbot/importmap-update@v1
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
```

That's the whole setup. Configuration is optional, and the defaults match what
you'd probably configure anyway.

## Grouping

Opening a pull request for every outdated package gets noisy fast, and rolling
all of them into one pull request makes for a diff nobody enjoys reviewing. The
action splits updates into security, patch, minor, and major buckets, and you
choose a strategy for each one in `.github/importmap-updates.yml`:

```yaml
version: 1

grouping:
  security: { strategy: individual }   # one PR per vulnerable package
  patch:    { strategy: grouped }      # one PR for all patch bumps
  minor:    { strategy: grouped }      # one PR for all minor bumps
  major:    { strategy: individual }   # one PR per major bump

open_pull_requests_limit: 10
labels: [dependencies, javascript, importmap]
branch_prefix: "importmap-updates"
```

Every field is optional. Both `open_pull_requests_limit` and
`open-pull-requests-limit` work, which saves you a round of debugging if you're
copying from a Dependabot config.

## Security updates are handled differently

A vulnerable package becomes a security pull request even when the fix happens
to be a major version bump. The body still records the bump kind, so reviewers
know to expect breaking changes before they open the diff.

Security pull requests are also exempt from `open_pull_requests_limit`. When the
budget is tight, we fill the remaining slots with major bumps first, then minor,
then patch, since the bigger bumps are the ones somebody needs to set aside time
for.

## What happens on the next run

An open pull request goes stale as soon as another version ships. On each run,
the action brings its own pull requests back in line with what's actually
outdated: the ones whose versions have moved get updated in place, and the ones
whose packages aren't outdated anymore get closed with a comment saying why.
Pull requests it didn't open are left alone, even on a branch matching your
configured prefix.

## Try it in dry-run mode first

Set `dry-run: "true"` and the action runs end to end without side effects. It
reads your importmap, builds the plan, compares it against your open pull
requests, and logs every operation it would have performed. That's worth doing
on a repository whose JavaScript dependencies haven't been looked at in a while,
before it opens 10 pull requests at once.

## Alternatives

[Depfu] is the only one I could find. It has supported import maps since 2023,
it's free for public repos, and it's a paid hosted service for private ones. If
you'd rather have one service watching your gems and your JavaScript together,
it's worth a look.

Issues and pull requests are welcome on [GitHub][repo].

[repo]: https://github.com/thoughtbot/importmap-update
[importmap-update]: https://github.com/marketplace/actions/importmap-update
[importmap-rails]: https://github.com/rails/importmap-rails
[dependabot-6675]: https://github.com/dependabot/dependabot-core/issues/6675
[Depfu]: https://depfu.com
