17 / 20 · Day 6
Day 6 · Concept 17

Node basics

Node lets JS run server-side. Standard library gives you filesystem, HTTP, child processes, streams, crypto. The async-by-default API and the event loop are the things that take getting used to.


1 · Filesystem

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

const text = await readFile("notes.txt", "utf8");
console.log(text);

await writeFile("out.txt", text.toUpperCase());

Always use the node:fs/promises API (async). The callback API and the sync API both exist; the promise API is the cleanest.

2 · HTTP server — without a framework

js server.mjs
import { createServer } from "node:http";

const server = createServer((req, res) => {
    if (req.url === "/health") {
        res.writeHead(200, { "Content-Type": "application/json" });
        res.end(JSON.stringify({ ok: true }));
        return;
    }
    res.writeHead(404);
    res.end("not found");
});

server.listen(3000, () => console.log("listening on :3000"));

Most apps use Express, Koa, Fastify, or Hono — but the stdlib server is enough for small services and is what frameworks build on.

3 · Process and env

js env.mjs
console.log(process.platform);    // 'darwin', 'linux', 'win32'
console.log(process.version);     // 'v20.10.0' etc.
console.log(process.argv);         // [node, script, ...args]
console.log(process.env.PORT);     // env var

// Exit
if (!process.env.API_KEY) {
    console.error("API_KEY required");
    process.exit(1);
}

4 · Useful built-in modules

ModuleFor
node:fs/promisesFilesystem (async)
node:pathPath joining, parsing
node:urlURL parsing
node:http / node:httpsServers and clients
node:cryptoHashing, HMAC, encryption
node:streamStreaming I/O
node:child_processRun sub-processes
node:worker_threadsCPU-bound work off the main thread
node:testBuilt-in test runner (Node 20+)

5 · Common mistakes

  • Sync filesystem on a server. readFileSync blocks the event loop. Use the promise API.
  • Forgetting to handle errors on streams. Unhandled errors crash the process.
  • Buffering full files instead of streaming. A 1 GB file readFile'd into memory will exhaust it.
  • Mutating process.env on the fly — works, but most config libraries snapshot at startup.

6 · When it clicks

  • You reach for the promise API before checking the docs.
  • You stream large files; you don't read them whole.
  • You know which work belongs in a worker_thread.
Found this useful?