Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Working with folders

Project files are easier to manage when sorted into folders: posts in data/posts, uploaded images in uploads. The node:fs/promises module has functions that create folders, list their contents and delete them.

Creating a folder

mkdir() creates a folder. With recursive: true it also creates any missing parent folders, and if the folder already exists it simply does nothing:

import { mkdir, stat } from 'node:fs/promises';
 
await mkdir('data/posts', { recursive: true });
 
console.log((await stat('data/posts')).isDirectory()); // true

The folders data and posts inside it appear next to the program.

Listing files

readdir() returns an array of the names inside a folder:

import { mkdir, readdir, writeFile } from 'node:fs/promises';
 
await mkdir('data/posts', { recursive: true });
await writeFile('data/posts/hello.md', '# Hello');
await writeFile('data/posts/files.md', '# Files');
 
const names = await readdir('data/posts');
 
console.log(names.sort()); // [ 'files.md', 'hello.md' ]

The order of names depends on the system, so the list is sorted for output.

Files and folders

With withFileTypes: true you get objects instead of strings, and they know whether they are a file or a folder:

import { mkdir, readdir, writeFile } from 'node:fs/promises';
 
await mkdir('data/posts', { recursive: true });
await mkdir('data/images', { recursive: true });
await writeFile('data/posts.json', '[]');
 
const entries = await readdir('data', { withFileTypes: true });
 
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
  console.log(entry.isDirectory() ? 'folder' : 'file  ', entry.name);
}

It prints "folder images", "folder posts" and "file posts.json".

Only the files you need

path.extname() helps pick files by extension:

import path from 'node:path';
import { mkdir, readdir, writeFile } from 'node:fs/promises';
 
await mkdir('drafts', { recursive: true });
await writeFile('drafts/a.md', 'A');
await writeFile('drafts/notes.txt', 'B');
 
const posts = (await readdir('drafts')).filter((name) => path.extname(name) === '.md');
 
console.log(posts); // [ 'a.md' ]

Deleting and moving

FunctionWhat it does
mkdir(dir, { recursive: true })Creates a folder with all parents
readdir(dir)Lists the names
rename(from, to)Renames or moves a folder
rm(dir, { recursive: true, force: true })Deletes a folder with everything inside

Be careful with rm(): deleted items do not go to the recycle bin.

Common mistake

Without recursive: true, mkdir() fails in two cases: when the folder already exists (EEXIST) and when the parent folder is missing (ENOENT). So a server that creates a data folder at startup always needs the option:

// src/server.js
import { mkdir } from 'node:fs/promises';
 
await mkdir('data', { recursive: true });

Then the second and later starts run without errors.

Thanks for reading!

Donate to the site — we work hard for you.