Logo Xingxin on Bug

What is a package.json?

July 20, 2025
6 min read
No tags available

I’ve built several web applications using next.js and astro. However, most of the time I start with a template and therefore the package.json is an untouched land for me. Therefore, I think it is time to research and make a Socratic Q&A session for myself.

Part 1: The Recipe Card – package.json

Question: I’ve just started a new project, and the first thing I see is a package.json file. In the simplest terms, what is its main job?

Answer: The package.json file is the recipe📝 for your project. There are few keywords in it.

  • the “ingredients” (dependencies) needed to make it run
  • the “kitchen tools” (devDependencies) used to build and test it
  • the “instructions” (scripts) for common tasks like serving or building the meal

Question: Okay, so it’s a manifest. Inside, I see two sections that look similar: "dependencies" and "devDependencies". What’s the real-world difference? Give me an example of a package you’d put in each one.

Answer:

  • dependencies: this is the ingredient🥣 of your meal. You won’t write your application from scratch. Instead, you need ingredients(libraries) from others to cook. These are just like the ingredient you bought from the supermarket.
  • devDependencies: this is the tool🥄 to prepare the meal. Example tools are like tsx, typescript, and prettier. You need the tool to better handle the ingredient. For example, use prettier to format the code is just like putting the ingredients in a proper order.

Question: I also see a "scripts" section with commands like "start" and "build". Why is this useful? What problem does it solve for me as a developer?

Answer:

  • The start and build are typical instructions preparing the meal.
  • When you see "dev": "vite --host --port 3000 --open", it’s just like "heating": turn on oven at 100 degree.
  • So when other run npm run dev, they are actually running npm run heating with specific parameters defined in this instruction🔥.

Part 2: The Chef – Package Managers (npm, pnpm, bun)

Question: Now that I have my “recipe” in package.json, how do I actually get the “ingredients” (the packages)? What role does a tool like npm or pnpm play here?

Answer:

  • The npm, pnpm and bun are the package manager. You list out the ingredients(package) in your package.json and they will help you to get the ingredients from an online store🛍️(the npm registry).
  • They will fetches the exact versions of all the ingredients (dependencies and devDependencies), and organizes them in your project’s node_modules folder.
  • The npm and pnpm could be considered as different type of dealer where they can get the same package but the cost from them are different. Most of the time, the performance⚡ among them are: bun > pnpm > npm.

Question: After I run npm install, a massive node_modules folder and a package-lock.json file appear. I understand node_modules holds the code, but why is the lockfile so important? Why can’t I just share the node_modules folder with my team?

Answer:

  • The lockfile could be considered as a check list📃 containing the detailed information of the package you prepare. The benefit of this is to provide such info to other chef. Ideally, the same ingredient with same instruction gives the same meal. The lockfile ensures this.

Part 3: The Rulebook – tsconfig.json

Question: I’ve decided to use TypeScript. Suddenly, I need a tsconfig.json file. What is its primary relationship with my TypeScript code (.ts files)? What does it do?

Answer: The tsconfig.json could be considered as a rule of conversion telling the TypeScript compiler exactly how to handle your TypeScript code.

Why do I need this? Can’t I execute the

directly?
No you can’t. Because eventually the .ts will be converted to .js code. Browsers and Node.js environments can’t execute TypeScript code directly. They only understand JavaScript.


Question: Inside tsconfig.json, I see options like "target": "ES2020" and "module": "ESNext". What are these options telling the TypeScript compiler to do? How does this help my code run in different environments, like an old browser?

Answer: These two options are critical for compatibility.

  • "target": This sets the JavaScript version of the output code. If you set "target": "ES5", TypeScript will convert your modern code into an older syntax that can run on very old browsers. If you set "target": "ES2020", it will keep modern features that newer browsers understand. It controls browser compatibility.
  • "module": This sets the module system for the output code. It dictates how the compiled JavaScript files will import and export from one another. "ESNext" tells it to use the modern import/export syntax, while "CommonJS" would tell it to use the older require() syntax for Node.js. It controls code organization.

Part 4: The Dialect – Modules (ESM vs. CommonJS)

Question: I see import React from 'react' in some modern tutorials, but const fs = require('fs') in older Node.js examples. I know these are different ways of sharing code between files. Which one is the modern standard, and why is it generally better to use it in new projects?

Answer: The import/export syntax is called ECMAScript Modules (ESM), and it is the modern, official standard for JavaScript. The older const fs = require('fs') syntax is called CommonJS (CJS).

ESM is preferred in new projects because:

  1. It’s the official standard that works in both browsers and Node.js.
  2. It allows for ” tree-shaking”, a process where build tools can automatically remove unused code, making your final application smaller and faster.
  3. Its syntax is generally considered cleaner and less ambiguous.

Remark

See here to how to distinguish them.