← Node & Express

Módulos y npm

¿Para qué sirve el `package.json` y qué hacen sus campos más importantes como `scripts`, `main` y `type`?

Ver respuesta — intenta responderla en voz alta primero

El package.json es el archivo de identidad y configuración de un proyecto Node. Describe el proyecto (name, version, description), dice cuál es su archivo de entrada (main), qué dependencias necesita (dependencies y devDependencies), qué comandos se pueden correr (scripts, que ejecutas con npm run <nombre>), y en qué sistema de módulos trabaja (type: "commonjs" o "module").

Piensa en el package.json como la "cédula" del proyecto. npm y Node lo leen para saber qué instalar, cómo arrancar y cómo tratar el código. Los campos clave:

  • name: el nombre del paquete. En minúsculas, sin espacios. Si publicaras a npm, este sería su identificador.
  • version: la versión actual del proyecto, en formato major.minor.patch (semver), por ejemplo 1.4.2.
  • description: una frase corta que explica de qué trata el proyecto.
  • main: el punto de entrada. Es el archivo que se carga cuando alguien hace require('tu-paquete'). Por defecto es index.js.
  • scripts: un objeto con atajos de comandos. Cada clave es un nombre y su valor es el comando de terminal que se ejecuta. Los corres con npm run <nombre> (por ejemplo npm run dev). Algunos nombres tienen atajo propio: start y test se pueden correr como npm start y npm test, sin el run.
  • dependencies: los paquetes que tu app necesita en producción para funcionar (por ejemplo express).
  • devDependencies: los paquetes que solo usas durante el desarrollo (por ejemplo nodemon, eslint, vitest). No se necesitan cuando la app ya corre en el servidor.
  • type: define el sistema de módulos por defecto. Con "commonjs" (o si lo omites) usas require/module.exports. Con "module" usas import/export (ESM).

Sobre scripts con más detalle: cuando corres npm run dev, npm busca la clave "dev" dentro de scripts y ejecuta ese comando en una shell, poniendo además los binarios de node_modules/.bin en el PATH. Por eso puedes escribir nodemon o eslint en un script aunque no estén instalados globalmente.

Un package.json real (recuerda: JSON no admite comentarios, así que abajo el JSON va limpio y la explicación de cada campo va aparte).

{
  "name": "mi-api",
  "version": "1.0.0",
  "description": "API REST de ejemplo con Express",
  "main": "src/index.js",
  "type": "commonjs",
  "scripts": {
    "start": "node src/index.js",
    "dev": "nodemon src/index.js",
    "test": "vitest run",
    "lint": "eslint ."
  },
  "dependencies": {
    "express": "^4.19.0"
  },
  "devDependencies": {
    "nodemon": "^3.1.0",
    "vitest": "^1.6.0",
    "eslint": "^9.0.0"
  }
}

Qué hace cada parte de ese archivo:

  • name / version / description: identifican el proyecto y su versión actual.
  • main: al hacer require('mi-api') se carga src/index.js.
  • type: "commonjs": el proyecto usa require y module.exports.
  • scripts.start: npm start arranca la app en modo normal con node.
  • scripts.dev: npm run dev arranca con nodemon, que reinicia el server al guardar cambios.
  • scripts.test: npm test corre las pruebas con Vitest.
  • scripts.lint: npm run lint revisa el estilo del código con ESLint.
  • dependencies: express es necesario en producción.
  • devDependencies: nodemon, vitest y eslint solo se usan al desarrollar.

Cómo se ven esos comandos en la terminal:

npm start        # corre el script "start" (atajo, sin "run")
npm test         # corre el script "test" (atajo, sin "run")
npm run dev      # corre el script "dev" (nombres personalizados necesitan "run")
npm run lint     # corre el script "lint"

Poner comentarios dentro del package.json. El JSON no permite comentarios (// o /* */), y si los agregas, npm fallará al leer el archivo con un error de parseo. Otro error frecuente es intentar correr un script personalizado sin run, por ejemplo escribir npm dev en lugar de npm run dev; solo start, test, stop y restart tienen atajo directo, el resto siempre necesita run.

"El package.json es el archivo de configuración e identidad del proyecto. Guarda el nombre, la versión y la descripción, define el punto de entrada en main, y separa las dependencias en dependencies, que son las de producción, y devDependencies, que son las de desarrollo. En scripts pongo atajos de comandos que corro con npm run, como npm run dev para levantar el server con nodemon; start y test tienen atajo propio y no necesitan el run. Y el campo type decide el sistema de módulos: commonjs para require, o module para import y export. Algo importante: el JSON no admite comentarios, así que nunca hay que meter // dentro del archivo."

Reto rápido

Tienes este scripts en tu package.json. ¿Con qué comando corres cada uno correctamente?

{
  "scripts": {
    "start": "node app.js",
    "seed": "node scripts/seed.js"
  }
}
Ver respuesta
  • start se puede correr como npm start (tiene atajo) o también como npm run start.
  • seed es un nombre personalizado, así que necesita run: npm run seed. Escribir npm seed daría error porque npm no lo reconoce como comando.