2026
Table of Contents
- 1 Event Loop & Non-Blocking I/O
- 2 Modules & npm
- 3 Callbacks & Promises
- 4 Async/Await
- 5 File System Operations
- 6 HTTP Servers
- 7 Debugging & Error Handling
- 8 Best Practices & Wrap-Up
Introduction
Welcome to Node.js Fundamentals!
This comprehensive course introduces you to Node.js, a powerful runtime environment that lets you build server-side applications using JavaScript. Whether you're a web developer looking to expand into backend development or a newcomer to programming, this course provides everything you need to master the fundamentals.
What You'll Learn
Throughout this course, you will understand:
- How Node.js works under the hood (the event loop, non-blocking I/O, and the callback queue)
- How to organize code with the module system and manage packages with npm
- Three approaches to async programming: callbacks, promises, and async/await
- How to read and write files, work with directories, and manage file I/O
- How to create HTTP servers, handle requests, and build simple APIs
- Professional debugging techniques and robust error handling strategies
- Best practices for production-ready applications
How to Use This Course
Each chapter follows a consistent structure: a comprehensive lesson explaining core concepts, followed by three progressively challenging coding challenges with complete solutions. You can read through the lessons to build understanding, then work through the challenges to practice.
Prerequisites: Basic JavaScript knowledge (variables, functions, objects). You'll need Node.js installed on your computer.
Time Commitment: Expect 3-4 weeks of dedicated study, working through one chapter per 2-3 days.
Let's begin your journey into Node.js development!
Node.js is built on an event-driven, non-blocking I/O model. This makes it incredibly efficient for I/O-heavy operations like reading files, querying databases, or handling network requests. Understanding the event loop is crucial to mastering Node.js.
The Event Loop
The event loop is the heart of Node.js. It continuously checks for tasks to execute:
- Call Stack: Synchronous code executes here immediately
- Web APIs/Event Loop: Async operations (timers, file I/O, network requests) are handed to the system
- Callback Queue: When async operations complete, their callbacks wait here
- Event Loop: Moves callbacks from the queue to the stack when it's empty
Even though the timeout is 0ms, it doesn't execute immediately. Synchronous code (console.log calls) runs first, then the event loop processes the timeout callback.
Blocking vs Non-Blocking I/O
Blocking I/O pauses execution until the operation completes. Non-blocking I/O starts the operation and continues executing other code.
❌ Blocking (Slow)
Program pauses. If reading 3 files takes 150ms each, total = 450ms.
✅ Non-Blocking (Fast)
Program continues. If reading 3 files concurrently at 150ms each, total = ~150ms.
Why Non-Blocking Matters
For a web server handling 1000 concurrent requests:
- Blocking approach: 1000 × 50ms = 50 seconds ❌
- Non-blocking approach: ~50ms total ✅
Node.js shines when you have many I/O operations happening concurrently. Its event-driven model handles thousands of connections efficiently without creating a thread per connection.
What You've Learned
- The event loop processes code in phases: call stack, async APIs, and callback queue
- Blocking I/O pauses execution; non-blocking I/O continues immediately
- Synchronous code always runs before async callbacks
- Node.js efficiently handles concurrent I/O operations
Node.js uses a module system to organize code. Modules are reusable pieces of code that export functionality for other files to use. npm (Node Package Manager) lets you download and manage third-party packages.
The Module System (CommonJS)
A module is just a JavaScript file. Use module.exports to share code:
npm and package.json
Every Node.js project has a package.json file that describes the project and its dependencies:
Installing Packages
Use npm to install packages from the registry:
This downloads the package to node_modules/ and updates package.json.
node_modules/ to git. Add it to .gitignore. When cloning a repo, run npm install to reinstall dependencies from package.json.
Key Concepts
module.exports
What a module shares. Can be a function, object, class, or anything.
require()
Load a module. Returns what the module exported.
Dependencies
Packages your app needs to run (installed in production).
devDependencies
Packages for development only (testing, linting).
Callbacks and Promises are two ways to handle async operations. Both have their strengths, and understanding both helps you read existing code and make informed choices.
Callbacks
A callback is a function passed to another function, called when an operation completes:
The Callback Hell Problem
Deeply nested callbacks become hard to read:
Promises
A Promise represents a value that will be available in the future. It has three states:
- Pending: Operation hasn't finished
- Resolved: Operation succeeded with a value
- Rejected: Operation failed with an error
Promise Chains
Chain operations with .then() for cleaner, more readable code:
Much cleaner than callback nesting! Each .then() receives the resolved value from the previous one.
Callbacks: Simple for single operations, but nest deeply for chains. Promises: Clean chains, better error handling with single .catch().
Async/await is syntactic sugar built on Promises. It lets you write asynchronous code that looks and feels synchronous—no more chains of .then() calls.
Async Functions
An async function always returns a Promise:
The await Keyword
await pauses execution until a Promise resolves. It can only be used inside an async function:
Async/Await vs Promises
Promise Chains
Async/Await
Error Handling with Try/Catch
Async/await uses standard try/catch for error handling:
Concurrent Operations
For independent operations, use Promise.all() to run them in parallel:
Use async/await for modern Node.js code. It's cleaner, easier to debug, and easier to understand than callbacks or promise chains.
The fs module lets you interact with files and directories. You can read, write, delete, and manipulate files using async operations.
Reading Files
Writing Files
Directory Operations
Appending to Files
Deleting Files
Common Patterns
- Process JSON: Read JSON file, parse it, modify, write back
- Process CSV: Read file, split lines, process data
- Copy file: Read source, write to destination
- Generate report: Collect data, format, write to file
The http module lets you create web servers. Clients send HTTP requests to your server, and your server sends back responses.
Creating a Basic Server
Understanding Request & Response Objects
The req object contains request information:
The res object sends responses:
Routing
Handle different URLs differently:
Sending JSON
Handling POST Requests
HTTP Status Codes
- 200: OK (success)
- 201: Created (resource created)
- 400: Bad Request (invalid input)
- 404: Not Found
- 500: Internal Server Error
For production apps, use Express.js instead of raw http module. Express provides routing, middleware, and many other conveniences.
Professional error handling and debugging are essential for production apps. You'll spend as much time debugging as coding—better tools and patterns make this easier.
Error Types
- TypeError: Wrong type (calling non-function)
- ReferenceError: Undefined variable
- SyntaxError: Invalid syntax
- RangeError: Value out of range
Try/Catch Blocks
Custom Error Classes
Create meaningful errors for your domain:
Logging
Use appropriate log levels:
Error Handling in Async Code
Debugging Tools
- console methods: log, warn, error, table, time
- Node debugger: node inspect app.js
- Chrome DevTools: chrome://inspect
- VS Code debugger: Built-in debugging
Stack Traces
Stack traces show the call chain when an error occurs. Read them from bottom to top to understand the sequence of function calls that led to the error.
Always handle errors. Never swallow them silently. Log, re-throw, or return a fallback value—but do something.
This final chapter reinforces best practices and covers what you need to know to deploy production applications.
Code Quality
- Use meaningful variable names
- Keep functions small and focused (single responsibility)
- Avoid deep nesting (max 3 levels)
- DRY: Don't Repeat Yourself
- Use a linter (ESLint) to enforce consistency
Async Best Practices
- Prefer async/await over callbacks and promises
- Use Promise.all() for independent concurrent operations
- Set timeouts for external API calls
- Implement retry logic for transient failures
Security Basics
- Input Validation: Validate all user input
- Environment Variables: No hardcoded secrets
- HTTPS: Always use TLS in production
- No Command Injection: Never execute user input as commands
- Error Messages: Don't expose stack traces to users
Performance Optimization
- No synchronous file/database operations
- Cache computed results when beneficial
- Use streams for large files (don't load into memory)
- Run independent operations concurrently
- Monitor and optimize database queries
Testing
Always test your code! Common frameworks:
- Jest: Full-featured testing
- Mocha: Flexible test framework
- Vitest: Fast unit tests
Course Summary
You've learned:
- How Node.js event loop and non-blocking I/O work
- How to organize code with modules and npm
- Three async patterns: callbacks, promises, async/await
- File system operations and HTTP servers
- Professional debugging and error handling
- Best practices for production applications
Next Steps
Where to go from here:
- Express.js: Learn the popular web framework (our next course)
- Databases: Learn MongoDB, PostgreSQL, or MySQL
- Real Projects: Build something useful and deploy it
- Testing: Master unit and integration testing
- DevOps: Learn Docker and deployment
Congratulations!
You now have a solid foundation in Node.js. You understand how to build efficient, scalable server-side applications with JavaScript. The next step is to build something—learning by doing is the most effective way to master these skills.
Happy coding! 🚀
Appendix: Resources & Further Learning
Official Documentation
- Node.js Official Docs: nodejs.org/docs
- Node.js API Reference: nodejs.org/api
- npm Registry: npmjs.com
Recommended Frameworks & Tools
- Express.js — Web application framework
- Jest — Testing framework
- ESLint — Code linter
- PM2 — Process manager
- Nodemon — Auto-reload during development
Learning Resources
- FreeCodeCamp — Comprehensive tutorials
- GitHub — Study open-source Node.js projects
- Stack Overflow — Search for answers to your questions
- Dev.to — Articles by Node.js developers
Hosting Platforms
- Heroku — Easy deployment, great for beginners
- AWS — Maximum control and scale
- DigitalOcean — Simple and affordable
- Google Cloud — Excellent tools and documentation
Key Takeaways
- Understand the event loop—it's the heart of Node.js
- Always use async/await for modern code
- Handle errors gracefully and log appropriately
- Test your code; bugs in production are expensive
- Security matters—validate input, use environment variables, never hardcode secrets
- Monitor your applications in production
- Keep learning—JavaScript and Node.js evolve constantly
Thank you for working through this course. You're now equipped with the knowledge to build production-ready Node.js applications. Good luck with your projects!