fs/promises es la versión basada en promesas del módulo fs de Node. Sus funciones (readFile, writeFile, readdir, stat, mkdir, rm, rename y el resto) devuelven una promesa en lugar de recibir un callback, así que las esperas con await y capturas los errores con try/catch. Impórtalo con require('fs/promises') o import fs from 'fs/promises'.
Imprime [ 'write docs', 'ship it' ]: cada await espera a que termine una operación antes de que se ejecute la siguiente línea, así que el append siempre ocurre después de la primera escritura. En un ES module await funciona en el nivel superior; en CommonJS, envuelve el código en una función async.
Las funciones que más vas a usar
Los nombres coinciden con la API de callbacks, sin el callback. Las páginas de readFile y writeFile cubren esas dos en detalle.
| Función | Qué hace | Se resuelve con |
|---|---|---|
readFile(path, 'utf8') | Lee un archivo entero | El contenido |
writeFile(path, data) | Crea o reemplaza un archivo | undefined |
appendFile(path, data) | Añade al final | undefined |
readdir(path) | Lista una carpeta | Un array de nombres |
stat(path) | Tamaño, fechas, archivo o carpeta | Un objeto Stats |
mkdir(path, { recursive: true }) | Crea carpetas | La primera carpeta creada, o undefined |
rename(from, to) | Mueve o renombra | undefined |
rm(path, { recursive: true, force: true }) | Borra un archivo o una carpeta | undefined |
Listar una carpeta con readdir y stat
readdir solo devuelve nombres. Llama a stat sobre cada uno para obtener su tamaño o distinguir archivos de carpetas, o pasa { withFileTypes: true } para obtener entradas que ya conocen su tipo.
El bucle imprime README.md 6 bytes, notes.txt 3 bytes y src folder. stat se rechaza con ENOENT para una ruta que no existe, lo que lo convierte en una comprobación rápida de existencia cuando además quieres los detalles.
Renombrar, mover y borrar
rename sirve para renombrar y para mover un archivo (dentro de la misma unidad). rm borra; necesita recursive: true para una carpeta con contenido, y force: true para no fallar cuando la ruta ya no existe.
El archivo pasa de drafts a published con su nuevo nombre, y después de rm la carpeta blog solo lista published. Quita force: true del segundo rm y se rechaza con ENOENT.
Manejar errores con try/catch
Una operación que falla rechaza su promesa. Con await, ese rechazo se convierte en una excepción que capturas como cualquier otra. El code del error te dice qué salió mal.
La primera llamada no encuentra el archivo y devuelve []; la segunda imprime Ada. Códigos que conviene conocer: ENOENT (no existe el archivo), EEXIST (ya existe), EISDIR (una carpeta donde se esperaba un archivo), ENOTEMPTY (una carpeta aún tiene contenido) y EACCES (sin permisos).
Una promesa a la que no haces await ni .catch() se convierte en un unhandled rejection cuando falla, y Node termina con un error. Haz await de cada llamada, o devuelve su promesa a quien sí lo haga.
Leer varios archivos a la vez con Promise.all
Un bucle for con await lee los archivos uno detrás de otro. Cuando las lecturas no dependen entre sí, lánzalas todas y espera una sola vez con Promise.all: el disco trabaja en todas a la vez.
Promise.all mantiene el orden del array de entrada, así que el resultado es [ 'alpha', 'beta', 'gamma' ] sin importar qué lectura terminó primero, y la longitud unida es 14. Cambia 'b.txt' por 'x.txt' en el array y todo el await se rechaza con ENOENT.
Si necesitas todos los resultados aunque fallen algunas lecturas, usa Promise.allSettled; la página de promesas cubre los dos.
Errores comunes
Confundir los dos módulos. require('fs').readFile espera un callback; require('fs/promises').readFile devuelve una promesa. Llamar a la versión con callback sin callback lanza The "cb" argument must be of type function.
Olvidar await. const text = fs.readFile(...) es una promesa pendiente, y text.split lanza text.split is not a function.
Escrituras en paralelo sobre un archivo. Promise.all con varias escrituras a la misma ruta puede dejar el contenido mezclado. Ejecútalas en secuencia.
Preguntas frecuentes
¿Qué diferencia hay entre fs.promises y fs/promises?
Ninguna. require('fs').promises y require('fs/promises') son el mismo objeto. La ruta fs/promises (o node:fs/promises) es la forma habitual de importarlo hoy.
¿Hay un existsSync en fs/promises?
No. La API de promesas tiene access, que se rechaza cuando la ruta no existe, pero lo habitual es llamar a la operación que necesitas y capturar ENOENT. existsSync del módulo fs normal sigue funcionando para comprobaciones rápidas.
¿fs/promises es más lento que la API con callbacks?
Un poco, por el coste de las promesas, pero es insignificante comparado con el tiempo de disco. Elige por legibilidad; la API de promesas es la que usa la mayoría del código nuevo.
¿Cómo convierto una función de fs con callback en una promesa?
Rara vez hace falta, porque fs/promises cubre las funciones de archivos. Para otras APIs con callbacks, util.promisify(fn) devuelve una versión que devuelve una promesa.