The role of a dependency in programming is analogous to that of beams and columns in a building. Just as beams and columns form the backbone of any structure, dependencies provide the foundation for building and running software. They simplify the software development process by offering ready-made functionalities that developers can leverage.
Given this critical role, it is essential for developers to thoroughly understand what dependencies are and how to integrate them effectively into projects. This article provides a broad overview of dependencies, their main categories, and common examples. However, it will not cover less common forms of dependencies, such as optionalDependencies and bundleDependencies.
What is a Dependency?
A dependency is an external package, resource, or piece of code that a software program relies on to function. For example, consider a program named A
, which includes two subprograms, B
and C
. These subprograms contain functions, variables, or files that program A
needs to execute properly. If program A
cannot access the functions and variables defined in B
and C
, it will encounter errors. Therefore, B
and C
are dependencies for program A
.
Types of Dependencies
In software development, dependencies are generally categorized into two broad types:
Direct Dependencies
Direct dependencies are the packages or resources that a codebase uses without the involvement of intermediary packages. Functions, variables, or files from these resources are directly incorporated into your code. Examples of direct dependencies include production dependencies, which are essential for the software’s functionality in a live environment, and development dependencies, which are needed during development.
Indirect (or Transitive) Dependencies
An indirect or transitive dependency occurs when a dependency with its own dependencies is included in a codebase, creating a chain of dependencies. This results in an indirect relationship between the codebase and the dependencies of the included dependency. An example of this transitive dependency arrangement can be seen with peer dependencies.
The upcoming sections will explain the examples of direct and transitive dependencies mentioned above in more detail and show you how to import them into a project
Production Dependencies
Production dependencies are the packages an application requires to function outside the development environment. In codebases, they are often simply referred to as "dependencies." Common examples of production dependencies include Bootstrap and React.
How to Install a Production Dependency
To install a package as a production dependency, run the following command in your terminal:
npm install <package-name> --save-prod
The --save-prod
flag is optional because npm includes this flag by default when you run the command. Therefore, you can omit the flag and rewrite the previous command as follows:
npm install <package-name>
You can also manually install a production dependency. For example, in a React project, you can do this by following these steps:
Open the
package.json
file in a code editor.Add an object named dependencies.
Within the dependencies object, add a dependency and its version number as a key-value pair, as shown below:
"dependencies": {
"dependency_name": "version_number"
}
Development (or Dev) Dependencies
Development dependencies are packages required only for local development and testing. Examples include testing tools like Jest and Enzyme, and code linters such as ESLint and StandardJS.
How to Install a Development Dependency
To add a package as a development dependency, run the following command:
npm install <package-name> --save-dev
Unlike production dependencies, you must include the --save-dev
flag when installing development dependencies. You can also add a development dependency manually. For example, in a React project, here’s how to do that:
Add an object named devDependencies to the
package.json
file.Within this object, list your packages and their version numbers as key-value pairs, as shown below:
"devDependencies": {
"enzyme": "^3.11.0"
"your_devDependency": "version_number"
}
Peer Dependencies
Peer dependencies let developers specify the host environment a package is compatible with. For example, if you publish a package to the npm registry and list React version 2.0 (or higher) as a peer dependency, it means that anyone using your package must also have React version 2.0 (or higher) installed in their project.
Unlike production and development dependencies, package managers like npm do not automatically install peer dependencies in a project. Instead, they issue a warning if they cannot find a listed peer dependency or encounter an incompatible version. The following snippet shows React listed as a peer dependency:
"peerDependencies": {
"react": "^2.0.0"
}
Moving Packages Between Dependencies
You can move packages between development and production dependencies. For example, to move a package from development to production, run the following command in your terminal:
npm install <package-name> --save-prod
Conversely, to move a package from production to development, run:
npm install <package-name> --save-dev
Common Questions About Dependencies
This section addresses some of the most frequently asked questions about dependencies.
Can React be a dev dependency?
Yes, React can be listed as a dev dependency. This does not prevent your app from compiling because Webpack, used by React for bundling, processes the import statements in your code regardless of React's placement in the
package.json
file.Do dev dependencies go into production?
No, devDependencies are meant for development purposes only and do not go into production.
What is the difference between a dependency and a peer dependency?
A dependency is a package that an application needs to run in production. In contrast, developers use peer dependencies to specify the host environment with which a package is compatible with.
Final Words
In this article, you explored the concept of dependencies in software development, including their major categories and examples. While other types of dependencies exist beyond those covered here, you now have a solid understanding of the most important ones. Properly grouping dependencies in your project enables package managers to install the necessary packages and environments for your app to run efficiently, thereby reducing bugs and easing maintenance.