Internet Garden
TimerAnimalBlog

📦 Dependencies and Package Managers in JavaScript/TypeScript

2025-07-06•Written by Frederic

This article provides a practical introduction to dependencies and package managers in the JavaScript/TypeScript ecosystem. You will learn what dependencies are, why they matter, and how package managers help you efficiently manage and maintain your projects.


What is a dependency, and why does it matter?

In software development, dependencies refer to an external piece of code, library, module, or package that a software project relies on to function correctly. External means you import external code in your current project, as it may seem that it does not make sense to code it yourself, is cumbersome or already works perfectly in other open-source projects. This external piece of code is like a black box: you often don't know how it works, but you get the intended output.

Engineers commonly share large amounts of code (especially within the JavaScript/TypeScript community) to avoid rewriting essential components (e.g., a datepicker), libraries, or frameworks. However, that means the entire ecosystem becomes more dependent on each other. For example, I depend on the open-source project lucide icon to have cute icons on Internet Garden.

It's critical to realise that practically all software is constructed on top of other software, which depends on other software. They are all dependent on each other, and if one heavily used project has bugs, it can cause massive difficulties in debugging or even widespread disruptions, as the left-pad incident has shown (read more).

Hence, I am not the biggest fan of dependencies. Especially in terms of compatibility issues. Whenever there is an update or a dependency change, it often takes me quite some time to debug it, which becomes tiresome. I have to read the error message, view what component breaks if it has other dependencies and what upgrade or downgrade would fix the issue. Removing and re-installing the runtime (like Node.js) often solves the issue.


Why do dependencies matter?

In my opinion, dependencies have three main advantages:

  • External code makes me as a developer more efficient and productive in the beginning: I can quickly extend this blog's capabilities by providing pre-built solutions for everyday tasks or functionalities, such as code text snippets, without building and testing them from scratch.

  • External code makes my code more modular and maintainable: Using dependencies facilitates modular design by breaking down complex systems into smaller, manageable components. This modular approach makes the codebase easier to understand, maintain, and update. At the same time, these dependencies will make my codebase harder to maintain due to their cross-dependencies. When I update my code, I always have to check, that it is alwats compatible. Hence, finding a balance between not having too many dependencies and being efficient is one of the difficulties in software engineering.

  • Integrations, Integrations, Integrations: Dependencies allow projects to integrate seamlessly with external systems, services, or platforms. For example, we often use supabase or tailwindcss in our projects, which makes us dependent on them. It helps us to move fast, but is also a calculated risk we are willing to take.

Hence, using dependencies can make development much more time-efficient; especially in the beginning. However, it also comes with maintenance and dependency costs over time, as the more dependencies you have, the more dependent you are and prone to bugs and vulnerabilities not caused by you. So, I personally strive to keep my codebase simpler (K.I.S.S. = Keep It Simple Stupid) and make sure I only use the absolute bare minimum of dependencies.


What is a package manager?

Before the advent of package managers, JavaScript engineers typically relied on a handful of dependencies stored directly within their projects or served via content delivery networks (CDNs). Handling an ever-increasing number of code package dependencies was a considerable pain, which is why package managers were born.

A package manager (i.e., a package-management system) is a software tool that systematically automates the steps involved in installing, updating, customising, and uninstalling computer programs, such as software packages. Packages contain metadata (usually the package.json file in most JavaScript/TypeScript applications), which provides an essential description of the program's name, an explanation of its function, the version number, the vendor, and a list of dependencies the program needs to operate. Hence, package.json is an extremely informational tool, and whenever you look at an existing project, I would always recommend reading it first to understand the scope of the project.

The purpose of a package manager is to eliminate the need for manual updates and installations, which is indispensable for most software applications.


Popular Package Managers

There are three popular package managers you will likely encounter frequently:

NameDescriptionNotes

npm (Node Package Manager)

npm is the default package manager for Node.js, a popular runtime environment for JavaScript. It hosts the largest ecosystem of open-source JavaScript packages (around 800’000 code packages) and is widely used for building web applications, server-side applications, and command-line tools.

I often use it, as it is the default and very commonly used. Especially when you read on StackOverflow instructions on handling your bug, it usually gives command line instructions with npm and not with other package managers, so you do not have to do the mental gymnastics of adjusting your command line.

Yarn

Yarn is a fast, reliable, secure JavaScript package manager developed by Meta as an alternative to npm. It is known for its speed and offline mode.

I used to work with Yarn quite often, but I encountered certain hiccups with it at times, so I do not use it in my projects. Sometimes, you may find yourself inadvertently mixing Yarn with npm, resulting in the creation of yarn.lock files. This can lead to complications when deploying to production environments.

PNPM (Pinned Node Package Manager)

PNPM is a lightweight and efficient package manager for Node.js applications. It optimises disk space and improves installation speed using a unique file-linking approach and a content-addressable store.

I use pnpm quite often nowadays.

In the end, it does not matter which package manager you use. I recommend trying all three in your projects to see which one you like best.


How to install a Package Manager to your project

To install a package manager on a new project, follow these steps by using the terminal:

Step 1: First, open your desired folder to create a new ex. Next.js project. You can navigate to the folder.

cd ../Desktop/yourCodeFolder

Step 2:

If you have never downloaded Node.js (a runtime environment), you should first do so. You can download and install Node.js from https://nodejs.org/. npm is installed by default with Node.js. Verify the installation and its version by entering node --version into your terminal.

Step 3:

Use either 1. npm, 2. yarn or 3. pnpm for your new project.

npm -v //1. npm is already installed automatically with Node.js. Check maybe the version

#or

npm install --global yarn //2. Yarn can be installed ironically through npm

#or

npm install -g @pnpm/exe //3. pnpm can also be installed through npm

Step 4:

You're ready to create a new project. This example uses Next.Js:

# Create a new Next.js project using npm
npx create-next-app@latest my-next-app

# Create a new Next.js project using Yarn
yarn create next-app my-next-app

# Create a new Next.js project using pnpm
pnpx create-next-app my-next-app

2 things to know:

1. .gitignore

A .gitignore file specifies intentionally untracked files that Git should ignore, such as sensitive information or unnecessary code, such as node.js, as any browser has its own runtime environment and does not need node.js. Some of your files listed in .gitignore contain sensitive information (like API keys), so they should not be tracked in your GitHub or any other version control, as it can cause vulnerability issues (if your GitHub data or API keys are leaked) and might cost a lot of money. Thus, be very careful with your .gitignore file.

2. Mixing package managers in one project

Mixing different package managers like npm, Yarn, and pnpm in one project is not advisable due to potential inconsistencies in dependency resolution and build reproducibility. Each package manager generates its own lock file (e.g., package-lock.json for npm, yarn.lock for Yarn, pnpm-lock.yaml for pnpm) to ensure consistent dependency versions across environments. Mixing package managers can lead to conflicts in lock file formats and undermine the purpose of lock files, compromising build reproducibility and introducing potential issues during development, testing, and production.

Conclusion:

Dependencies and package managers are vital for modern software development, especially in the JavaScript/TypeScript realm. They enable efficiency, code reuse, and integrations with external systems. While managing dependencies can be challenging, package managers like npm, Yarn, and pnpm streamline the process.

I hope this article helps you to choose a package manager you prefer and gives you more confidence in building your own projects. Let me know what you think of this blog post and happy building :-).

© 2025 Internet Garden