Node.js I/O

Node.js File System

El módulo fs permite leer, escribir y monitorear archivos. Utiliza la API de promesas, gestiona las rutas de forma segura y usa streams para cualquier contenido voluminoso.

intermediate14 min readUpdated 15 sept 2026
config.js
js
// config.js
import { readFile, writeFile } from "node:fs/promises";
import path from "node:path";

const file = path.join(import.meta.dirname, "config.json");

const config = JSON.parse(await readFile(file, "utf8"));
config.updatedAt = new Date().toISOString();

await writeFile(file, JSON.stringify(config, null, 2));
Módulo
node:fs/promises
Rutas
node:path
Codificación
utf8 para texto
Directorios
mkdir, readdir, rm
Archivos grandes
Streams
Seguridad
Evitar path traversal

Por que importa

Por qué es importante el manejo de archivos

Almacenamiento persistente

Los archivos guardan configuraciones, subidas, logs y salidas generadas que deben sobrevivir a un reinicio.

La seguridad es fundamental

Las rutas no confiables y las lecturas sin límite son dos de las vulnerabilidades más comunes en el lado del servidor.

El streaming mantiene la memoria estable

Procesa archivos grandes mediante streams en lugar de cargarlos en búfer, para que la memoria no crezca según el tamaño del archivo.

La imagen completa

Los tres pilares del trabajo con archivos

Leer y escribir contenido, gestionar rutas y directorios de forma segura, y usar streams para archivos grandes.

Contenido

Leer y escribir

Leer, escribir y añadir contenido a archivos, utilizando una codificación para el texto.

Rutas

Localizar

El módulo path une, resuelve y normaliza rutas entre diferentes plataformas.

Streaming

Escalar

Usa streams para archivos grandes y pipelines para el procesamiento de datos.

El sistema de archivos de un vistazo

Las APIs principales

readFile y writeFile

Lee y escribe archivos completos como una cadena de texto o un buffer.

mkdir y readdir

Crea y lista directorios.

módulo path

join, resolve, basename, extname y normalize.

stat

Verifica existencia, tamaño, tipo y marcas de tiempo.

watch

Reacciona a cambios en archivos para servidores de desarrollo y herramientas.

Streams

createReadStream y createWriteStream para grandes volúmenes de datos.

Una breve historia

De fs basado en callbacks a I/O basado en promesas

  1. 2009

    fs con Callbacks

    Node expone el acceso a archivos a través de callbacks con el error primero.

    09
  2. 2014

    Propuesta de fs.promises

    Se diseña una API basada en promesas para el JavaScript moderno.

    14
  3. 2019

    fs/promises estable

    Los métodos de promesas se convierten en la forma recomendada de usar fs.

    19
  4. 2023

    Soporte para Glob

    Los patrones glob integrados eliminan una dependencia común.

    23
  5. Hoy

    Prioridad a las Promesas

    El acceso asíncrono a archivos es el estándar; las APIs síncronas quedan para scripts y el arranque.

    Hoy

La guia completa

Node.js File System: Todo lo que necesitas saber

Por qué es importante el manejo de archivos

Los servidores leen y escriben archivos constantemente: configuraciones, subidas, logs, cachés, reportes generados y resultados de compilación. El módulo node:fs de Node.js es la interfaz, y la forma en que lo utilices determinará si tu servidor se mantiene responsivo y si tus datos permanecen seguros.

Hay tres aspectos fundamentales. Utiliza la promise API para que el event loop permanezca libre. Construye las rutas de forma segura para evitar que la entrada del usuario pueda salir de un directorio. Y utiliza streams para archivos grandes para que el consumo de memoria no aumente según el tamaño del archivo.

Lectura y escritura de archivos

La API de promesas es la opción predeterminada para el código de la aplicación.

// files.js
import { readFile, writeFile, appendFile } from "node:fs/promises";

// text
const text = await readFile("notes.md", "utf8");
await writeFile("notes.md", text + "\nnew line\n", "utf8");
await appendFile("app.log", "event\n", "utf8");

// binary
const image = await readFile("photo.png"); // Buffer
await writeFile("copy.png", image);

Pasa una codificación como "utf8" para obtener un string; omítela para obtener un Buffer de bytes raw. writeFile reemplaza el archivo, mientras que appendFile añade contenido a este. Ninguno de los dos crea directorios faltantes, por lo que debes llamar a mkdir primero cuando sea necesario.

Directorios

// dirs.js
import { mkdir, readdir, rm, rename, stat } from "node:fs/promises";

await mkdir("data/cache", { recursive: true });

const entries = await readdir("data", { withFileTypes: true });
for (const entry of entries) {
  if (entry.isDirectory()) console.log("dir", entry.name);
}

const info = await stat("data/cache");
console.log(info.size, info.mtime);

await rename("data/tmp.json", "data/final.json");
await rm("data/old", { recursive: true, force: true });

recursive: true hace que mkdir y rm operen sobre árboles completos, y withFileTypes devuelve entradas que puedes validar sin llamadas adicionales a stat. Usa stat para verificar la existencia, el tamaño y las marcas de tiempo, pero ten en cuenta que sigue los symlinks; lstat no lo hace.

Rutas

El módulo node:path se encarga de la manipulación de rutas de forma portable.

// paths.js
import path from "node:path";

const file = path.join("uploads", "avatars", "ada.png");
const absolute = path.resolve("uploads", "ada.png");
const name = path.basename(file);          // ada.png
const ext = path.extname(file);            // .png
const dir = path.dirname(file);            // uploads/avatars

Utiliza path.join y path.resolve en lugar de la concatenación de strings, y import.meta.dirname (o import.meta.url en versiones anteriores) para localizar archivos relativos al módulo actual. En Windows, path utiliza barras invertidas, razón por la cual la concatenación manual falla.

Seguridad: path traversal

La vulnerabilidad de archivos más común es permitir que la entrada del usuario escape del directorio previsto.

// safe-path.js
import path from "node:path";

const BASE = "/srv/uploads";

function safePath(name) {
  const target = path.resolve(BASE, name);
  if (target !== BASE && !target.startsWith(BASE + path.sep)) {
    throw new Error("Invalid path");
  }
  return target;
}

Resuelve la entrada contra una base fija y luego verifica que el resultado siga estando dentro de ella. Asimismo, valida los nombres de archivo, rechaza los bytes nulos y nunca expongas errores crudos del sistema de archivos a los clientes. Consulta la guía de Web Security.

Escrituras atómicas

Si ocurre un fallo durante la escritura, un lector podría ver un archivo escrito a medias. Para el estado y la configuración, escribe en un archivo temporal y renómbralo en su lugar.

// atomic.js
import { writeFile, rename } from "node:fs/promises";
import { randomUUID } from "node:crypto";

const tmp = `/srv/state/.${randomUUID()}.tmp`;
await writeFile(tmp, JSON.stringify(state), "utf8");
await rename(tmp, "/srv/state/current.json");

rename es atómico dentro del mismo sistema de archivos, por lo que los lectores siempre verán el archivo antiguo o el nuevo completo.

Streaming de archivos grandes

Para cualquier contenido que pueda ser voluminoso, utiliza streaming en lugar de buffering.

// stream.js
import { createReadStream, createWriteStream } from "node:fs";
import { pipeline } from "node:stream/promises";

await pipeline(
  createReadStream("big.csv"),
  createWriteStream("copy.csv"),
);

El streaming mantiene el uso de memoria estable y permite comenzar el procesamiento antes de que se haya leído el archivo completo. La guía de Streams cubre transforms, backpressure y object mode.

Monitoreo de archivos

// watch.js
import { watch } from "node:fs";

const watcher = watch("./config", { recursive: true }, (event, filename) => {
  console.log(event, filename);
});

process.on("SIGINT", () => watcher.close());

Los watchers son ideales para servidores de desarrollo y recargas de configuración. Implementa un debounce para ráfagas de eventos, gestiona eliminaciones y renombrados, y cierra siempre el watcher para que el proceso pueda finalizar.

Mejores prácticas

  • Usa node:fs/promises en el código de la aplicación.
  • Lee y escribe con una codificación explícita, o espera un Buffer.
  • Construye rutas con node:path y resuélvelas respecto a una base conocida.
  • Protégete contra el path traversal en cualquier nombre de archivo proporcionado por el usuario.
  • Usa streams para archivos grandes; carga en buffer solo lo que necesites completo.
  • Escribe archivos de estado de forma atómica usando un archivo temporal y renombrándolo.
  • Cierra los watchers y los file handles para que los procesos puedan finalizar correctamente.

Errores comunes

  • Usar readFileSync en un request handler.
  • Concatenar la entrada del usuario en las rutas (paths).
  • Asumir que un directorio existe antes de escribir.
  • Leer un archivo enorme en memoria y provocar un crash bajo carga.
  • Exponer errores crudos del sistema de archivos y filtrar rutas.
  • Olvidar cerrar los watchers o streams.

Próximos pasos

El manejo de archivos es una tarea cotidiana en el servidor. Profundiza con los Streams, comprende la planificación en la guía del Event Loop y refuerza la seguridad de tus rutas con la guía de Web Security.

Leer un archivo

Usa la API de promesas en servidores para que el event loop permanezca libre. Las llamadas síncronas bloquean todas las demás solicitudes.

Preferido
import { readFile } from "node:fs/promises";

const text = await readFile("data.json", "utf8");
Evitar
import { readFileSync } from "node:fs";

// blocks the whole server
const text = readFileSync("data.json", "utf8");

Construir una ruta

Resuelve la entrada del usuario contra una base fija y rechaza cualquier cosa que se salga de ella. La concatenación de cadenas invita al path traversal.

Preferido
import path from "node:path";

const base = "/srv/uploads";
const target = path.resolve(base, name);

if (!target.startsWith(base + path.sep)) {
  throw new Error("Invalid path");
}
Evitar
// "../../etc/passwd" escapes
// the intended directory
const target = "/srv/uploads/" + name;

Preguntas frecuentes

Preguntas frecuentes

Keep learning

Related topics from the roadmap.

$ comienza a aprender

Listo para aprender File System?

Nuestro tutorial interactivo te guia a traves de File System paso a paso — con quizzes y codigo real que puedes ejecutar en el navegador.