Jul 28, 2025·8 min read

Dependency review checklist before adding a new library

Use this dependency review checklist to assess maintenance risk, license fit, transitive packages, bundle size, and exit cost before your team adds a library.

Dependency review checklist before adding a new library

Why one more library matters

Most teams do not get hurt by the first library. They get hurt by the pile of small choices that looked harmless at the time.

Every package adds code your team did not write, test, or fully understand. That code still runs in your app, touches your data, and can fail in ways your team now has to debug.

The risk is easy to miss when the library solves a tiny problem. A date helper, form tool, or markdown parser can pull in many transitive dependencies, and each one brings its own update cycle, license terms, and security history.

That means one install rarely stays one install. You are often accepting a chain of packages maintained by people your team has never met and may never review until something breaks.

The work also does not end after npm install or adding a package to your lockfile. Maintainers ship new versions, bugs appear, APIs change, and security issues show up months later. Your team inherits that maintenance burden the moment the library lands in production.

This is where a dependency review checklist earns its keep. It slows down a quick decision by five minutes, which can save days of cleanup later.

Exit cost is the part many teams skip. If the library spreads through twenty files, shapes your data model, or sits in the center of your UI, replacing it later gets expensive fast. You do not just swap a package. You rewrite code, retest behavior, update docs, and fix edge cases you forgot were there.

A small team feels this even more. If two developers save three hours by adding a helper today but spend two weeks removing it next quarter, the math was bad from the start.

Writing a little more code yourself is not always the best choice. But adding a new library should clear a higher bar than "it works". It should be small enough to trust, stable enough to live with, and easy enough to remove if it turns into a problem.

Start with the need

Most bad dependency choices begin when a team grabs a package before naming the problem clearly. Start with one sentence that says what you need to do, where it runs, and any limit that matters.

Keep that sentence narrow and testable. "We need to parse CSV files up to 10 MB on the server" is clear. "We need better data handling" is not. If the need is fuzzy, the library choice will be fuzzy too.

Then check what you already have. Teams often add a package for work the language, browser, framework, or standard library already handles well enough. That happens all the time with date formatting, HTTP requests, UUIDs, small utility helpers, and simple validation.

Compare a few real options before anyone approves anything:

  • use built in features only
  • use one small library with a narrow job
  • write a small internal helper for the cases you actually have

A dependency review checklist works best when the team agrees on a few simple rules ahead of time. The package should meet your maintenance bar, fit your software license rules, stay within your size limit, keep transitive dependencies under control, and have a reasonable exit cost if you remove it later.

Exit cost is easy to miss. A tiny package can still spread through dozens of files and turn into glue code you must unwind later. If replacing it would take two days, say that before you add it.

Record the decision while it is fresh. Write who reviewed it, which options you compared, and why the team said yes or no. A short note in the pull request is enough. Six months later, that note will save time when someone asks why the package is there at all.

Check who maintains it

A library can look popular and still be a risky pick. Stars and download counts tell you that people noticed it. They do not tell you whether someone still fixes bugs, answers security reports, or keeps up with new versions of the language and framework.

Start with the release history. A healthy project usually shows recent releases, clear version notes, and a pace that makes sense for its size. Long gaps are not always bad, but they need a reason. If the tool changes your build, auth, or data layer, a quiet repo should make you pause.

Open the issues tab and read a few pages, not just the totals. Look for reports about security holes, broken installs, memory leaks, and version conflicts. Pay attention to unanswered issues that sit for months. That often tells you more than a polished README.

One maintainer is not an automatic no. It is a risk you should name clearly. If one person handles every release, every review, and every support question, your team depends on that person staying interested and available. For a tiny helper package, that may be fine. For something deep in your stack, it usually is not.

Release notes help you spot another pattern: surprise breakage. If every other release changes APIs, renames options, or drops support with little warning, your future upgrade cost goes up fast. A good dependency review checklist should treat this as maintenance risk, not as a small annoyance.

Docs matter more than teams admit. Check whether the docs answer common setup problems, show upgrade steps, and explain limits. If you cannot solve a basic install issue in ten minutes, your team will probably lose hours later when something goes wrong.

Check the license against your rules

A package can look cheap on day one and turn expensive later if its license does not fit how your team ships software. Check the license in two places: the published package and the source repo. If they do not match, stop and clear that up before you merge anything.

Most teams need a short internal rule set. It can be as simple as: allowed, allowed with review, and not allowed. MIT, BSD, or Apache 2.0 often pass with little friction. GPL or AGPL need a closer look because they can affect how you distribute software or network services.

Read past the license name. Some packages add terms in the README, a separate NOTICE file, or a commercial addendum. That is where teams get caught. A library may be free for personal use but not for commercial work. Another may require attribution in product docs or app screens.

Do not stop at code files. Check bundled assets too, especially when a package ships with:

  • fonts
  • icons or images
  • sample data
  • model files
  • media codecs

Those files may use different terms than the code around them.

A quick example: a small team adds a chart library under a permissive license, then learns the included icon set has a separate attribution rule. The code is fine, but the shipped app is now out of policy. That kind of miss is easy to avoid if someone checks the whole package, not just the top line in the repo.

If the wording feels fuzzy, ask legal early. A ten minute question before adoption is cheaper than swapping out a library after release. When legal approves a package, save that decision in your internal notes so the next reviewer does not have to start from zero.

Count the packages it pulls in

Review architecture before install
A short advisory session can prevent weeks of rewrites after a package spreads across the codebase.

A library rarely arrives alone. You install one package, and it may pull in 15, 40, or 120 more through transitive dependencies. That changes the review fast, because your team now owns the risk of that whole chain.

Small packages can hide big baggage. A simple helper for parsing dates, rendering markdown, or reading files might drag in a full framework, old utility packages, or build tools you did not plan to ship.

Before anyone installs it in the main branch, inspect the dependency tree. Most package managers can show what will come along for the ride, and the package manifest often gives away the shape of the stack.

What usually deserves a closer look

  • Packages that have not seen updates in a long time
  • Utilities you already ship elsewhere under a different name
  • Native modules that need local builds or system libraries
  • Postinstall scripts that run code on developer machines or CI
  • One narrow feature that pulls in a large framework

Old transitive dependencies are easy to miss because they sit two or three levels down. They still count. If one outdated package breaks your install, triggers security alerts, or stops working with a new runtime, your team still has to deal with it.

Duplicates are another quiet cost. You may already ship one date library, one schema validator, or one HTTP client. Add a new library with its own favorites, and you now carry two ways to do the same job.

Native modules and postinstall scripts deserve extra suspicion. They often turn a quick install into platform-specific bugs, slower CI, and painful onboarding for new developers.

A good dependency review checklist should treat package count as a proxy for future work. If a library solves a small problem but adds a large tree, write down the number and compare it with a simpler option or a short in-house wrapper. That five-minute check can save days of cleanup later.

Measure size and runtime cost

A library can look small in the README and still hit your app hard after install. Check the installed package size, not the marketing number. Then check what lands in your final build, because those are often very different.

Run the test in a real build, not a toy sample. Add the package to the actual app, create a production build, and compare the output before and after. That shows whether the code really gets tree-shaken or whether side effects pull in more than you expected.

A quick bundle size audit should answer four plain questions:

  • How many kilobytes did the final bundle gain?
  • Does the package load on startup or only when a user reaches one screen?
  • Does memory use jump after import or first use?
  • Does it slow cold starts on serverless or mobile devices?

Runtime cost matters as much as file size. A date library, markdown parser, or analytics SDK might add only a modest amount to the bundle but still slow startup, keep extra objects in memory, or trigger work on every page load. Those costs show up later as slower screens, higher hosting bills, or weaker battery life.

Check each environment you ship. Browser, server, and mobile builds often behave differently. A package may be harmless on the server, heavy in the browser, and painful on low-memory phones.

Watch for side effects in the package settings. If the library marks files as having side effects, your build tool may keep code you never call. If it ships CommonJS only, tree shaking may work poorly compared with an ESM build.

A small team can test this in one afternoon. Install the package, build the app, open the slowest screen, record startup time and memory, then remove it and compare. If the numbers move more than expected, keep looking for a lighter option.

Price the exit before you commit

Most teams estimate setup time and ignore removal time. That is a mistake. A library can look cheap on day one and turn expensive six months later, when it sits in dozens of files, shapes your data, and sneaks into tests, build scripts, and user flows.

A solid dependency review checklist should ask one plain question: if this library starts causing trouble, how hard will it be to remove? If the honest answer is "painful," treat that as part of the cost now, not later.

The easiest way to lower exit cost is to hide the library behind your own interface. Keep one thin layer in your code that says what your app needs done, and let that layer call the library. Then the rest of the codebase talks to your interface, not to the package directly. This takes a little more time up front, but it can save days of cleanup later.

Direct calls all over the codebase create a mess fast. If twenty files import the same package and each file uses it a bit differently, replacing it becomes a search-and-rewrite project with lots of small bugs. One wrapper file is boring. Boring is good.

Save a few real sample inputs and outputs too. If you ever swap the library, you will need a quick way to check that the new one behaves close enough to the old one. A handful of saved cases often catches odd formatting, date parsing, rounding, or edge-case behavior before it reaches users.

Watch for lock-in around data formats and outside APIs. Some packages do more than help your code. They create database records, write config files, store metadata, or depend on a vendor-specific API shape. That means migration work may include:

  • converting stored data
  • rewriting tests and fixtures
  • changing API adapters
  • updating docs and team habits

A small team sees this all the time with auth, analytics, payments, and editor libraries. The library itself may take an hour to install. Removing it can take a week. If you write down that exit cost before adding a new library, you make calmer choices and avoid sticky shortcuts.

A simple example from a small team

Plan the removal path
Design thin wrappers and ownership notes now so future swaps stay manageable.

A developer needs better date formatting for one reporting screen. The screen shows daily totals, a date range, and a few timestamps. Nothing else in the app uses advanced date math, so the team does not approve a new package on instinct.

They run a short dependency review checklist and compare three options:

  • native browser and runtime APIs for formatting and parsing
  • a small package that handles the few formats they need
  • a large date suite with extra locale, timezone, and helper features

Native APIs almost work, but one report needs a cleaner parsing helper and more readable formatting code. The large suite solves that fast, but the first install tells a bad story. It adds more code than the page needs, pulls in old transitive dependencies, and makes the bundle heavier for every user who opens that screen.

The small package lands in the middle. It covers the exact formats the team needs, adds little weight, and keeps the code easy to read. Just as important, the team can swap it out later without touching half the app. That matters more than people think. Exit cost gets expensive when date helpers leak into every file.

They set one rule for the implementation: wrap the package in a tiny local utility. The app calls formatReportDate() instead of calling the library everywhere. If the package goes unmaintained next year, one file changes instead of thirty.

The team also writes down why they chose it. Two lines in the project notes are enough: one reporting screen, small package, no large suite because of weight and old transitive packages. The next time someone suggests adding a new library, the review goes faster because the team already has a sane default.

Common mistakes during review

Teams usually make the same few mistakes when they review a package. The pattern is simple: someone needs a feature fast, finds a library that looks popular, and stops checking too soon. That is how small choices turn into slow builds, license problems, or code nobody wants to touch six months later.

A dependency review checklist helps most when it catches boring mistakes early, not when release week is already tense.

  • Stars are a weak signal. A package can have a huge GitHub count and still have stale releases, open security issues, or one tired maintainer doing all the work.
  • License checks often happen far too late. Then legal or procurement steps in right before launch, and the team has to replace code under pressure.
  • Dev dependencies get ignored because they do not ship to users. They still run in CI, slow every pipeline, and can break builds after a minor update.
  • Teams often pull a large package for one tiny helper. A full date library to format two timestamps or a giant utility package for one function is usually a bad trade.
  • Nobody plans the exit. If the feature changes, the library stays behind and becomes dead weight because nobody wrapped it or documented how to remove it.

One small example shows how this happens. A team adds a test tool and two plugins for a quick feature branch. The code ships, but the tool stays in CI, adds several minutes to every run, and later blocks a Node upgrade. Nobody meant to create that problem. They just did not treat build-time packages as real dependencies.

The fix is not more process. It is better questions. Check maintenance, check the license, count what comes along for the ride, and ask one blunt question before merge: if we need to remove this later, how painful will that be?

Quick checks before you merge

Audit your package choices
Ask Oleg to review package risk, license fit, and exit cost before you merge.

A new package can look harmless in a pull request and still create months of extra work. Before anyone merges, run the same five checks every time. A short dependency review checklist beats a long comment thread.

  • State the exact problem the library solves, who owns that choice, and why your current code or tools do not already cover it.
  • Confirm the license matches your policy. If the team needs legal approval, pause the merge until you get it.
  • Count the transitive dependencies, not just the package you install directly. A small tree is easier to track, update, and remove.
  • Measure the cost in the real app. Check bundle growth, startup time, memory use, and any extra CPU or network work.
  • Add one exit note to the pull request: how you would replace the library later, what code depends on it, and what might make removal painful.

A small example helps. Say a team adds a date library for one formatting task. The package itself looks small, but it pulls in locale data, adds 70 KB to the client bundle, and touches code in six files. That does not mean "reject it." It means the team should write down why that tradeoff is fine, or pick a smaller option.

This review does not need a meeting. One person can fill it out in a few minutes, and the reviewer can challenge weak answers before the change lands. Teams that do this well move faster later because they leave fewer surprises in the codebase.

If the owner is clear, the license fits, the package tree stays reasonable, the size change stays inside your budget, and the exit plan is written down, the merge is usually safe enough to approve.

What to do next

Make the decision easy to find later. Add a short note in the repo or team docs with the library name, why you chose it, what risk you accepted, and who approved it. Five clear lines beat a long memo.

That note should also say when you will check the package again. If the library has weak maintenance, a strict license, heavy transitive dependencies, or a real size cost, set a review date a few months out. Three to six months is a sensible rhythm for anything that feels risky.

A simple dependency review checklist works best when the team actually uses it. Keep it short enough that people will fill it in during a pull request, not after a problem shows up in production.

You do not need much:

  • one short decision note
  • one owner for follow-up
  • one review date for risky packages
  • one clear reason to remove the package later if it stops helping

Removal deserves the same attention as approval. If a package no longer saves time, delete it. Old dependencies stay around because nobody owns the cleanup, and then the team pays for them in updates, security alerts, and extra test work.

This gets more useful when you apply it across products. A shared template, a small set of rules, and a regular cleanup habit will catch most bad additions before they spread through the stack.

If your team wants that kind of practical process, Oleg Sotnikov can help set it up as a Fractional CTO or advisor. His work with startups and smaller companies focuses on simple engineering rules that cut waste without slowing the team down.