What you'll learn
Node.js combines a JavaScript engine with server-oriented host APIs. Production programs treat the process, environment, modules, events, and shutdown lifecycle as explicit boundaries.
By the end of this lesson, you'll be able to:
- Use Node ESM and process APIs
- Build a small command-line program
- Handle signals and graceful shutdown
Core mental model
Use this decision table as a compact reference. Focus on what each tool means and when it earns its place in production code.
| Concept | What it means | Decision rule |
|---|---|---|
| Process | Running program with arguments, environment, streams, and exit status | Treat environment and arguments as untrusted configuration |
| EventEmitter | Synchronous in-process event dispatch | Use for local lifecycle signals, not hidden global messaging |
| Signal | Operating-system request such as SIGTERM | Stop accepting work and release resources before exit |
Professional workflow
Build the behavior in small, observable steps. Each step should leave something you can inspect or test.
- Describe the Node process boundary: inputs, outputs, state, timing, and expected failures.
- Implement the smallest correct path with names that expose intent.
- Add edge cases and failure handling before introducing abstractions.
- Verify behavior with realistic data and one deliberately adversarial example.
- Refactor only after the observable behavior is protected.
Make behavior observable
Guided code lab
Parse a focused CLI contract
The program validates arguments and sets a meaningful exit code on misuse.
const [, , command, course] = process.argv;
if (command !== "open" || !course) {
console.error("Usage: node course-cli.js open <course>");
process.exitCode = 1;
} else {
console.log("Opening " + course);
}Shut down gracefully
Signal handling closes owned resources before allowing the process to end.
let closing = false;
async function shutdown(signal) {
if (closing) return;
closing = true;
console.log("Received", signal);
await server.close();
}
process.on("SIGTERM", () => shutdown("SIGTERM"));
process.on("SIGINT", () => shutdown("SIGINT"));Production practice
Contract
Make the Node process boundary explicit with validated inputs, structured outputs, owned resources, and stable failures.
Verification
Exercise normal work, invalid input, dependency failure, concurrency, and graceful cleanup in automated tests.
Operations
Use structured logs, health signals, timeouts, and configuration that can change without editing source code.
Common failure mode
Independent workshop
Build a course-report CLI that reads arguments, configuration, and emits JSON or human-readable output.
Your finished workshop must include:
- Validated commands and exit codes
- ES module organization
- Signal-aware cleanup
Definition of done
Recap & quick check
Key takeaways
- Node adds server host APIs
- The process is a boundary
- Events are synchronous by default
- Graceful shutdown protects in-flight work
Quick check
1. Where are CLI arguments exposed?
2. What is a safer validation failure than immediate process.exit()?
3. What commonly requests production shutdown?
Keep the workshop. Later modules deliberately build on these decisions, so each exercise can become part of your final portfolio architecture.