Software dependencies let a team build on shared, maintained code instead of recreating everything. They also bring versions, licences, updates and security decisions that somebody still needs to own.
01
A dependency is code your application relies on
A business application can contain a relatively small amount of code written specifically for the business and still rely on hundreds of other software packages.
That is not automatically a problem. It is how modern software gets built without every team recreating database connections, authentication, date handling, file storage, testing tools and interface components from scratch.
The problem starts when those packages become invisible. A dependency is easy to add during development and easy to forget once the feature works. Years later, the application may depend on an old library nobody understands, a package that has stopped receiving updates or a chain of smaller packages that never appeared on the original technical plan.
This article follows an imagined customer document portal built with Laravel and Vue. It explains what software dependencies are, why direct and transitive packages both matter, how lockfiles keep installations repeatable and how to manage updates without choosing between two bad extremes: update everything immediately or never update anything at all.
A software dependency is a library, framework, package, module or service that another piece of software needs to build, run or behave as expected. Sonatype describes dependencies in similar terms and separates them into direct and transitive relationships.
Our portal might use Laravel as its PHP framework, a package to create PDF reports, a cloud storage library and Vue packages for the interface. The development environment may also use tools for automated testing, code formatting and asset building.
Some dependencies are needed while the application is running. Others are only needed while developers build or test it. npm records these categories as dependencies and devDependencies. Composer makes a similar distinction through its normal and development requirements.
The distinction helps with deployment and maintenance, but it does not make development packages irrelevant. A compromised build tool or broken test dependency can still affect the route by which software reaches production.
02
Direct dependencies are only the first layer
A direct dependency is one the project deliberately declares. If the portal's composer.json asks for a PDF library, that library is direct. If package.json lists a Vue component library, that is direct too.
Those packages have dependencies of their own. The PDF library may need an image parser. The image parser may rely on a lower-level utility. These are transitive dependencies, often described as dependencies of dependencies.
The developer did not choose each transitive package individually, but the application still relies on the full chain. A security problem, licence issue or incompatible release deep in that tree can eventually affect the portal.
This is why counting the visible entries in composer.json or package.json does not describe the whole application. The package manager's resolved dependency tree gives a more honest picture.
03
Good dependencies save time for the work that is actually different
Reusing maintained software is usually sensible. A mature framework can provide routing, validation, database access and security features that would take a team a long time to rebuild well. A well-chosen library can also give the project a familiar interface and a community that finds problems before one application encounters them alone.
The benefit is not simply speed. Shared packages can improve consistency and let the team concentrate on the workflow that makes the portal valuable: collecting documents, assigning reviews, recording decisions and keeping customers informed.
Rebuilding common plumbing is not automatically safer. Home-grown authentication, encryption or payment code can create more risk than a carefully selected, actively maintained dependency.
The useful question is therefore not whether dependencies are good or bad. It is whether each dependency earns the responsibility it adds.
04
Choosing a package is an architecture decision
npm install and composer require make adding a package look cheap. The command takes seconds. The commitment can last for years.
Before using a package for an important part of the portal, look beyond its download count. Consider:
- whether the package is actively maintained;
- how often it releases fixes and how it handles security reports;
- whether its documentation and upgrade notes are clear;
- how large a dependency chain it introduces;
- whether its licence fits the intended use;
- whether the application would be tightly coupled to its interface;
- whether a realistic replacement exists if maintenance stops;
- whether the team can test the behaviour that matters.
A small utility used in one isolated place creates a different commitment from an authentication package woven through every request. The closer a dependency sits to customer data, access control, payments or deployment, the more carefully its ownership and replacement route should be considered.
Popularity is useful evidence, but it is not a maintenance plan. A widely used package can still change ownership, become abandoned or no longer fit the application's version of PHP, Node.js, Laravel or Vue.
05
The manifest asks for versions and the lockfile records the answer
Package manifests such as composer.json and package.json describe the project's dependency requirements. Those requirements often use version constraints rather than one exact version.
For example, a project might allow compatible releases within a major version. Semantic Versioning uses a three-part major.minor.patch number. In its specification, patch releases contain compatible bug fixes, minor releases add compatible functionality and major releases may contain incompatible changes.
That convention helps teams communicate change, but it is not a substitute for testing. Package maintainers can make mistakes, projects can interpret compatibility differently and version zero packages are explicitly considered unstable under the Semantic Versioning specification.
The lockfile records the exact dependency tree selected when the packages were resolved. Composer's documentation recommends committing composer.lock for applications so developers, continuous integration and production use the same versions. npm says package-lock.json describes the exact generated tree and is intended to be committed to the source repository.
Without a lockfile, two installations performed on different days can resolve different packages while both satisfy the manifest. That makes a failed deployment or environment-specific bug much harder to explain.
A lockfile does not freeze the application forever. It makes change deliberate. The team updates dependencies, reviews the lockfile change, runs tests and then deploys a known result.
06
Security alerts need context and an owner
Package managers and repository tools can report known vulnerabilities. npm audit checks the configured dependency tree against registry vulnerability information. composer audit checks installed packages against advisories and can also report abandoned or malware-flagged packages. GitHub Dependabot alerts monitor supported dependency manifests and alert when a known vulnerability affects the repository.
These tools are useful, but an alert is the start of a decision rather than the end of one.
The team still needs to ask:
- Is the affected dependency present in production or only in development?
- Does the application use the vulnerable feature or code path?
- Is the service exposed in a way that makes exploitation realistic?
- Is a fixed version available?
- Can the package be updated without a breaking change?
- Does a temporary control reduce exposure while a proper fix is tested?
- Who owns the decision and when will it be reviewed again?
Severity matters, but context matters too. Automatically applying every possible update can break a working service. Dismissing every alert as theoretical can leave a known route into customer data. A good response makes the exposure, fix, test and owner visible.
07
Regular small updates are usually calmer than rare large ones
Dependencies create maintenance work whether the team schedules it or not.
If the portal avoids updates for three years, a security fix may arrive alongside major changes to PHP, Laravel, Node.js, the database driver and the build system. Each change becomes harder to isolate. Documentation for the old combination becomes scarcer, and the team may need to cross several unsupported versions before reaching a maintained one.
Updating every package the day it releases is not necessary either. A sensible rhythm separates routine maintenance from urgent security work.
The exact schedule depends on the application's exposure and importance, but the decision pattern is stable:
| Situation | Evidence to review | Sensible next move | Mistake to avoid |
|---|---|---|---|
| Compatible patch or minor update | Changelog, automated tests, lockfile diff and staging behaviour | Group small low-risk updates into a regular maintenance cycle | Treating a green version number as proof that nothing can break |
| New major version | Upgrade guide, deprecated features, framework support and test coverage | Plan it as a visible change with enough time to remove incompatibilities | Hiding a major upgrade inside unrelated feature work |
| Known vulnerability | Affected versions, exploit conditions, application exposure and fixed release | Prioritise by real risk, assign an owner and record any temporary control | Ignoring the alert or running an unsafe automatic fix without review |
| Abandoned package | Last release, open issues, maintainer notice, usage in the application and replacement options | Isolate, replace, remove or consciously take ownership | Waiting for an emergency before learning how deeply it is embedded |
| Transitive dependency issue | Full dependency tree and which direct package introduced it | Update or replace the direct package, or use a carefully tested temporary constraint | Editing installed package files by hand |
Small updates are easier to test, review and reverse. They also keep the team familiar with the dependency tree instead of turning it into an archaeological site.
08
An abandoned package is a business continuity question
A package does not need a dramatic security incident to become a risk. It may simply stop keeping pace with the platform around it.
Imagine the portal's PDF package has not released an update for two years. It still works, but the next supported PHP version exposes warnings and the maintainer no longer responds to issues. The immediate temptation is to leave it alone because customers can still download their reports.
That may be reasonable for a short period if the exposure is understood. It is not a long-term answer.
The team needs to learn how the package is used, what application code depends on its interface and whether another maintained library can produce equivalent documents. Keeping the package behind a small internal service can make replacement easier. Letting its API spread throughout controllers, jobs and templates makes the eventual move larger.
If no replacement fits, the options become more deliberate: maintain a private fork, fund upstream work, reduce the feature, build a narrow replacement or accept the risk for a defined period. Each option has a cost. The important part is that somebody has made the decision before the next platform upgrade makes it for them.
09
Know what is in production
An application cannot manage dependencies it cannot identify.
At minimum, keep the manifest and lockfiles in version control, review dependency changes in pull requests and make sure production deployments install from the committed lock. Automated inventory and software bill of materials tools can help larger estates understand which versions run across several applications.
Visibility also includes licences. Composer can list the name, version and licence of installed packages. Other ecosystems provide similar reports. A permissive licence, copyleft licence and commercial package do not create the same obligations, so legal or procurement advice may be needed when the use is important or unclear.
OWASP's Software Component Verification Standard treats supply-chain assurance as more than a scanner. It connects technical controls with business decisions about exposure, regulation, cost and available people. That is a useful boundary: tools can show the dependency tree and known problems, but the organisation still decides which risks it accepts and who owns the response.
10
Give dependency maintenance a simple operating rhythm
The process does not need to begin with an expensive platform. A maintained application can start with a repeatable routine:
- keep manifests and lockfiles committed;
- run dependency and vulnerability checks in continuous integration;
- review alerts at a defined frequency and immediately when the risk is urgent;
- assign an owner rather than leaving alerts in a shared queue;
- apply small updates through normal code review, tests and staging;
- record why a package is pinned or an alert is temporarily accepted;
- review abandoned and unsupported packages before a forced platform upgrade;
- remove packages that no longer earn their place;
- include dependency state in application handovers and technical reviews.
The portal may have excellent automated tests and still need a human decision about a major framework upgrade. It may have no known vulnerabilities and still depend on an abandoned package that blocks the next PHP release. Security, compatibility and maintainability overlap, but they are not the same question.
11
Borrow the code, keep the responsibility
Our imagined portal did not become unsafe because it used Laravel, Vue, a PDF package or a storage library. Those dependencies helped the team build a useful customer workflow without recreating common software.
The risk appeared when the dependency chain became nobody's job.
Treat package choice as part of architecture. Commit the lockfiles. Keep the full tree visible. Review security information with context. Prefer regular small updates to heroic rescue work. Know what you will do when a dependency stops moving.
The code may come from somebody else. The reliability of the application still belongs to the business running it.
If an important Laravel, PHP or Vue application has accumulated old, vulnerable or abandoned packages, I can help review the dependency tree, separate urgent exposure from routine maintenance and plan the smallest safe route forward.
Useful questions
Questions to ask about the dependencies in an important application
- Which packages does the application choose directly, and what transitive dependencies do they bring?
- Are the manifest and lockfiles committed and used consistently in deployment?
- Which packages sit close to authentication, customer data, payments or the build pipeline?
- Do dependency and vulnerability checks run automatically?
- Who owns each alert, accepted risk and planned update?
- Are small compatible updates reviewed regularly?
- Which packages are abandoned, unsupported or blocking a platform upgrade?
- Does each important package have a realistic replacement route?
- Are package licences understood for the way the software is used?
- Would an application handover show the next owner how to maintain the dependency tree?


