Streamlining Dependency Updates using RenovateBot
Author

Date Published
Share this post
Category: Engineering | ~8 min read

Dependency updates are something that everyone agrees should happen more often, but nobody wants to own it. Left unchecked, dependencies drift. Security patches go unnoticed. Minor version bumps accumulate until they become major version migrations. Multiply that across dozens of repositories spanning Ruby, Python, Go, Terraform, Helm, and Node.js, and you have a problem that doesn't scale with human attention.
At Fullscript, we set up RenovateBot as a self-hosted dependency update platform that any project in our GitLab instance can plug into with a few lines of configuration. It scans repos, detects outdated packages, and opens merge requests automatically: for everything from Ruby gems to Terraform providers to Helm chart versions.
This is the story of how we built it, how any team at Fullscript can adopt it, and the gotchas we ran into along the way.
Why Renovate?
We evaluated Dependabot and RenovateBot. Renovate won based on few reasons:
- Self-hosted on GitLab: We run our own GitLab instance, and Renovate has first-class GitLab support with a self-hosted runner model. No external service needs access to our code.
- Multi-manager support: Our shared preset enables 16 package managers out of the box: Bundler, Go, npm, pip and others. One tool covers our entire stack.
- Highly configurable: Package rules, grouping, scheduling, post-upgrade tasks, rate limits. Each project can tune its behavior while inheriting sensible defaults.
- Dependency Dashboard: An auto-managed GitLab issue that gives you a bird's-eye view of every pending update, every open MR, and every dependency that's been intentionally held back.
A Plug-and-Play Platform
The key design decision was making Renovate a platform, not a per-project setup. We built a shared infrastructure that any GitLab project can adopt with minimal effort.
Onboarding a Project
For a typical project, onboarding takes about 10 minutes:

That's it. Renovate will start scanning your repo on the next scheduled run and opening MRs for outdated dependencies.
Tested Across Every Language
We maintain dedicated test projects for every supported ecosystem to validate that the shared infrastructure works before teams adopt it: Ruby (Bundler), Python (pip), Node.js (npm), Node.js (Yarn), Ruby + Yarn, Go, Helm, Terraform.
Production Adoption
Beyond the test suite, Renovate is actively managing dependencies in production projects including hw-admin (our Rails monolith), aws-terraform (our infrastructure-as-code), and rx (our developer CLI tool).
The Dependency Dashboard
One of Renovate's most useful features is the Dependency Dashboard, and it's enabled by default in our shared preset.
When Renovate runs against your project, it creates (and maintains) a single GitLab issue titled Dependency Dashboard. This issue serves as a central control panel:
- Pending updates: Every dependency with an available update is listed and grouped by type (major, minor, patch). You can see at a glance how far behind you are.
- Open MRs: All currently open Renovate MRs are tracked here, with their status and any blocking issues.
- Rate-limited updates: If Renovate hit the PR limit and couldn't create all MRs, the remaining ones are listed here. They'll be created on the next run.
- Ignored or held-back dependencies: Dependencies you've configured to ignore (like
opensearchoractivemerchantinhw-admin) show up so the team remembers they exist. - Checkbox-driven control: You can tick checkboxes on the dashboard to force-create MRs for specific updates, retry failed ones, or rebase existing ones. Renovate reads these checkboxes on its next run and acts accordingly.
The dashboard turns dependency management from a check the Gemfile and hope exercise into something visible and actionable. When a team opens the issue, they see exactly what's outdated, what's in progress, and what's blocked — without running any commands.


Pushing the Limits: hw-admin
Most projects have a straightforward Renovate integration. Our Rails monolith, hw-admin, demonstrates how far you can push the configuration when a project has complex build requirements.
Dual lockfiles: We use Bootboot to maintain Gemfile.lock and Gemfile_next.lock, testing against upcoming Ruby and Rails versions without blocking current development.
Sorbet RBI generation: We use Sorbet for gradual typing. Any gem update needs to regenerate RBI (Ruby Interface) files via bin/tapioca gem, which boots the Rails environment to inspect gem type signatures.
Post-upgrade pipeline: Every dependency update triggers a five-step sequence: Renovate creates branch -> bundle install -> bundle install Dependencies_Next=1 -> bin/next update -> bin/tapioca gem -> Update lockfiles + RBI -> Merge Request Ready
Smart grouping and safety guardrails. Related gems are grouped: aws-sdk-*, sorbet-*, flipper-* each get a single MR. A 3-day minimum release age on all rubygems avoids catching issues in the first days after a release. Merge confidence badges show the community's experience with each update. Specific gems are auto-assigned to the right team members.
Gotchas and Lessons Learned
Renovate is a powerful tool, but it has sharp edges, especially in a self-hosted setup. Here are the issues we ran into and what we learned from each.
The config hierarchy is deceptive
Renovate has two distinct config scopes that look similar but behave very differently:
- Repo config (
.gitlab/renovate.json, presets) - Controls what Renovate does with your dependencies. - Self-hosted config (
config.js, env vars, CLI) - Controls how Renovate runs as a platform.
Renovate filters environment variables
By default, Renovate only passes a limited set of environment variables to child processes — including post-upgrade commands. This is a security measure designed for public CI runners, but it can trip you up on self-hosted infrastructure. Flags exposeAllEnv, customEnvVariables helps ensuring env vars are propagated correctly.
Size your runners for post-upgrade tasks
The Renovate job itself is lightweight, but post-upgrade commands can be heavy. If your post-upgrade tasks boot a Rails app, run compilers, or do anything memory intensive, the default runner size may not be enough. An OOM kill (exit code 137) during post-upgrade tasks is a sign you need to override the runner tag in your project's CI config.
Testing Renovate changes is awkward
Renovate only runs on the default branch by design, since it needs to create MRs from the base branch. This means you can't easily test config changes on a feature branch. We had to create temporary branch overrides in the shared template to test on non-default branches, then clean up after. If you're setting up Renovate, consider building a dry-run mechanism early.
The platform approach pays off
Building Renovate as shared infrastructure, a preset + CI template that any project can include, was the right call. New projects get dependency automation in 10 minutes without understanding Renovate internals. The test projects across all ecosystems catch regressions before they reach production repos. And project-specific complexity stays in the project's own config, not in the shared layer.
What We Have Today
Our Renovate platform handles dependency updates across our entire GitLab instance:
- 16 package managers enabled by default: from Bundler to Terraform
- Plug-and-play onboarding: Include the CI template, add a config file, and you're running
- Dependency Dashboard: Every project gets a live overview of its dependency health
- Smart defaults: Automatic labeling (major/minor/patch), rate limiting, and rebasing
- Per-project customization: Package grouping, post-upgrade tasks, team auto-assignment, ignored dependencies, and merge confidence badges
The mundane work of keeping dependencies current happens automatically, freeing developers to focus on the work that matters.
Share this post
Related Posts

Using Nitro for Terraform deprecations
Use Nitro in Linear to automate repetitive Terraform updates and generate PRs instantly at scale.

How PMs Use Nitro for Small Code Changes
Nitro empowers PMs to ship changes faster, reduce overhead, and collaborate without interrupting dev teams.