In the previous lesson you followed a cycle you know well: write code, save, run node src/catalog.js, read the output, fix, repeat. That cycle is fine for building a program, but it is painfully slow when what you want is to answer a small question: how does reduce behave with this array? What exactly does Object.entries return for a session? What is the total capacity of the Auditorio Ribera?
That is what the REPL is for: an interactive interpreter where you type an expression and see the result instantly. It is one of the most underrated tools in the ecosystem and, used well, it saves hours. In this lesson you will learn to handle it fluently and to explore Escena Viva's data live before writing it into a script.
Contents
- What a REPL is and what it is for
- Starting the REPL and evaluating expressions
- The
_variable and the result of declarations - Autocompletion, history and navigation
- The dot commands
- Loading the Escena Viva catalog into the REPL
- Exploring and transforming the data live
- The
.editormode for multi-line functions - Running one-off code without the REPL:
node -eandnode -p - Quirks: promises, top-level
awaitand other surprises - When to use the REPL and when not to
- What a REPL Is and What It Is For
REPL stands for Read-Eval-Print-Loop. It is a loop that:
- Reads (Read) what you type.
- Evaluates (Eval) it as JavaScript code.
- Prints (Print) the result.
- Loops (Loop) round, waiting for the next line.
flowchart LR
R["Read<br/>reads your line"] --> E["Eval<br/>runs the code"]
E --> P["Print<br/>shows the result"]
P --> L["Loop<br/>waits for the next one"]
L --> R
It is not a Node peculiarity: the browser console is a REPL, and so are python, irb and psql. Their value lies in the zero cost of experimenting: trying something out requires no files and no remembering paths.
Real day-to-day uses:
- Checking the exact behavior of an array method you do not use often.
- Verifying a regular expression before putting it into your code.
- Exploring the shape of some data you have just received.
- Converting values quickly (dates, cents to euros, bytes to megabytes).
- Checking what an installed module exports, without reading its documentation.
- Starting the REPL and Evaluating Expressions
Type node with no arguments:
The > symbol means the REPL is waiting for a line. Try:
> 2 + 2 4 > 'Teatro' + ' ' + 'Almendra' 'Teatro Almendra' > [1, 2, 3].map((n) => n * 10) [ 10, 20, 30 ] > Math.round(2500 / 100) 25
The REPL keeps state between lines: the variables you declare go on existing.
> const venue = 'Auditorio Ribera' undefined > venue.toUpperCase() 'AUDITORIO RIBERA' > venue.length 16
It also works with multi-line code: if a line is incomplete, the prompt changes to ... and the REPL waits for you to close it.
> const session = {
... id: 'ses-001-1',
... capacity: 420,
... sold: 180
... }
undefined
> session.capacity - session.sold
240To leave: .exit, or Ctrl+D, or Ctrl+C twice.
- The
_ Variable and the Result of Declarations
_ Variable and the Result of DeclarationsThe undefined result of declarations
You will have noticed something puzzling: when you typed const venue = 'Auditorio Ribera' the REPL answered undefined. That is not an error. The REPL prints the value of the expression it evaluated, and in JavaScript a variable declaration produces no value at all: it produces undefined.
> const price = 2500 undefined > price // Now yes, this is an expression whose value is 2500 2500 > let x = 10; x // Trick: separate with ";" to see the value 10
The same happens with function, class, loops and console.log (which returns undefined after printing):
The first line is what console.log printed; the second is its return value. In time you stop noticing it.
The _ variable
_ holds the result of the last expression evaluated. It is wonderfully handy for chaining explorations without declaring intermediate variables.
There is a sibling variable, _error, which holds the last error thrown:
> JSON.parse('{ this is not json }')
Uncaught SyntaxError: Expected property name or '}' in JSON at position 2
> _error.message
"Expected property name or '}' in JSON at position 2"Careful: if you manually assign
_ = 5, you lose this feature for that session (the REPL warns you). Avoid using_as a variable name of your own.
- Autocompletion, History and Navigation
These keys turn the REPL into something genuinely fast:
| Key | Effect |
|---|---|
Tab |
Autocompletes. If there are several options, press it twice to list them |
↑ / ↓ |
Moves through the command history |
Ctrl+R |
Reverse search in the history (type part of the command) |
Ctrl+A / Ctrl+E |
Go to the start / end of the line |
Ctrl+U |
Delete the whole line |
Ctrl+L |
Clear the screen |
Ctrl+C |
Cancel the current line (twice: exit) |
Ctrl+D |
Exit |
Autocompletion is the jewel. Type an object and a dot, then press Tab:
> const session = { id: 'ses-001-1', capacity: 420, sold: 180 }
undefined
> session.
session.__proto__ session.constructor session.hasOwnProperty
...
session.capacity session.id session.soldIt also works with built-in modules, which turns it into instant documentation:
> const path = require('node:path')
undefined
> path.
path.basename path.dirname path.extname path.join
path.normalize path.parse path.relative path.resolveThe history is kept between sessions in the file ~/.node_repl_history. You can close the REPL, open it tomorrow and get back with ↑ whatever you tried today.
- The Dot Commands
Anything starting with . in the REPL is an instruction to the REPL itself, not JavaScript.
| Command | What it does |
|---|---|
.help |
Lists every available command |
.break |
Abandons a half-written multi-line expression (alias: Ctrl+C) |
.clear |
Resets the context: deletes all your variables |
.editor |
Enters multi-line editor mode |
.exit |
Leaves the REPL |
.load <file> |
Loads and evaluates a file in the current session |
.save <file> |
Saves everything you have typed in the session to a file |
An example of the full .load / .save cycle:
.save writes out every line you typed (not the results). It is a convenient way to rescue an exploration that went well and turn it into the starting point of a script.
.break rescues you from the classic dead end:
Without .break (or Ctrl+C), the REPL would wait forever for the closing brace.
.clear deserves a warning: it resets the context and you lose every variable you defined. Use it when you want to start from scratch, not by accident.
- Loading the Escena Viva Catalog into the REPL
Here is where .load earns its keep. We are going to prepare a file containing only the data, with no presentation logic and no argument filtering, so that we can load it cleanly into the REPL.
Create src/catalog-data.js:
// src/catalog-data.js
// Just the catalog data, with no presentation logic.
// In module 2 we will add module.exports here so it can be reused
// from other files; for now it lets us load it into the REPL with .load
const catalog = [
{
id: 'evt-001',
title: 'Concierto de Otono',
venue: 'Teatro Almendra',
category: 'concert',
durationMinutes: 95,
sessions: [
{ id: 'ses-001-1', dateTime: '2026-10-03T20:00:00', capacity: 420, sold: 180, priceCents: 2500 },
{ id: 'ses-001-2', dateTime: '2026-10-04T19:00:00', capacity: 420, sold: 96, priceCents: 2200 }
]
},
{
id: 'evt-002',
title: 'Noche de Monologos',
venue: 'Sala Boveda',
category: 'comedy',
durationMinutes: 80,
sessions: [
{ id: 'ses-002-1', dateTime: '2026-10-10T21:30:00', capacity: 120, sold: 118, priceCents: 1800 },
{ id: 'ses-002-2', dateTime: '2026-10-11T21:30:00', capacity: 120, sold: 45, priceCents: 1800 },
{ id: 'ses-002-3', dateTime: '2026-10-17T21:30:00', capacity: 120, sold: 12, priceCents: 1500 }
]
},
{
id: 'evt-003',
title: 'Festival de Jazz de Primavera',
venue: 'Auditorio Ribera',
category: 'festival',
durationMinutes: 240,
sessions: [
{ id: 'ses-003-1', dateTime: '2027-04-17T19:00:00', capacity: 900, sold: 640, priceCents: 3800 },
{ id: 'ses-003-2', dateTime: '2027-04-18T19:00:00', capacity: 900, sold: 720, priceCents: 4200 }
]
}
];Now, from the project root:
The REPL shows the contents of the file as it evaluates it line by line. When it finishes, the catalog constant exists in your session:
An important point:
.loadis not the same asrequire..loadcopies and evaluates the text of the file inside the REPL's context, as if you had typed it.requireloads an isolated module and gives you only what that module exports. That is why.loadworks even when the file exports nothing, and why it is the ideal tool for exploring. Real modules arrive in Module 2.
- Exploring and Transforming the Data Live
With the catalog loaded, the fun begins: trying transformations out before writing them into the script.
Seeing the shape of the data
> catalog.map((e) => e.title) [ 'Concierto de Otono', 'Noche de Monologos', 'Festival de Jazz de Primavera' ] > catalog[1].sessions.length 3
To inspect a nested object without Node truncating it with [Object]:
filter: keeping part of the catalog
> catalog.filter((e) => e.venue === 'Sala Boveda').map((e) => e.title) [ 'Noche de Monologos' ] > catalog.filter((e) => e.durationMinutes > 90).map((e) => e.title) [ 'Concierto de Otono', 'Festival de Jazz de Primavera' ]
flatMap: flattening every session
The sessions are nested inside each event. To work with all of them at once:
And if we need to know which event each one belongs to, we add that information while flattening:
> const sessions = catalog.flatMap((e) => e.sessions.map((s) => ({ ...s, event: e.title, venue: e.venue })))
undefined
> sessions[0]
{
id: 'ses-001-1',
dateTime: '2026-10-03T20:00:00',
capacity: 420,
sold: 180,
priceCents: 2500,
event: 'Concierto de Otono',
venue: 'Teatro Almendra'
}The ... (spread) operator copies every property of the original object and adds the new ones. We will study it formally in the next lesson.
reduce: business totals
> sessions.reduce((sum, s) => sum + s.capacity, 0) 3000 > sessions.reduce((sum, s) => sum + s.sold, 0) 1811 > const revenue = sessions.reduce((sum, s) => sum + s.sold * s.priceCents, 0) undefined > revenue 6428600 > revenue / 100 64286
Sixty-four thousand two hundred and eighty-six euros of accumulated revenue. This is exactly the kind of question you answer in twenty seconds in the REPL and would take five minutes to code, save and run.
sort and find
> sessions.filter((s) => s.venue === 'Auditorio Ribera').map((s) => s.id)
[ 'ses-003-1', 'ses-003-2' ]
> [...sessions].sort((a, b) => b.priceCents - a.priceCents)[0].id
'ses-003-2'
> sessions.find((s) => s.sold / s.capacity < 0.2)
{ id: 'ses-002-3', ... }Note the [...sessions] before sort: sort mutates the original array. Copying it first avoids altering the data you are exploring. It is a classic mistake that the REPL helps you discover.
Occupancy by venue
> const byVenue = {}
undefined
> for (const s of sessions) { byVenue[s.venue] = (byVenue[s.venue] ?? 0) + s.sold }
undefined
> byVenue
{ 'Teatro Almendra': 276, 'Sala Boveda': 175, 'Auditorio Ribera': 1360 }
> console.table(byVenue)The ?? operator returns the right-hand value only when the left-hand one is null or undefined. We will look at it in detail in the next lesson.
- The
.editor Mode for Multi-Line Functions
.editor Mode for Multi-Line FunctionsTyping a ten-line function into the REPL line by line is awkward: if you get the third one wrong, you cannot go back. That is what .editor is for.
> .editor
// Entering editor mode (Ctrl+D to finish, Ctrl+C to cancel)
function venueSummary(events, venue) {
const sessions = events
.filter((event) => event.venue === venue)
.flatMap((event) => event.sessions);
const capacity = sessions.reduce((total, s) => total + s.capacity, 0);
const sold = sessions.reduce((total, s) => total + s.sold, 0);
return {
venue,
sessions: sessions.length,
capacity,
sold,
occupancy: `${Math.round((sold / capacity) * 100)}%`
};
}Press Ctrl+D to leave editor mode and evaluate the whole block at once. Then try it out:
> venueSummary(catalog, 'Teatro Almendra')
{ venue: 'Teatro Almendra', sessions: 2, capacity: 840, sold: 276, occupancy: '33%' }
> ['Teatro Almendra', 'Sala Boveda', 'Auditorio Ribera'].map((v) => venueSummary(catalog, v))> console.table(['Teatro Almendra', 'Sala Boveda', 'Auditorio Ribera'].map((v) => venueSummary(catalog, v))) ┌─────────┬────────────────────┬──────────┬──────────┬──────┬───────────┐ │ (index) │ venue │ sessions │ capacity │ sold │ occupancy │ ├─────────┼────────────────────┼──────────┼──────────┼──────┼───────────┤ │ 0 │ 'Teatro Almendra' │ 2 │ 840 │ 276 │ '33%' │ │ 1 │ 'Sala Boveda' │ 3 │ 360 │ 175 │ '49%' │ │ 2 │ 'Auditorio Ribera' │ 2 │ 1800 │ 1360 │ '76%' │ └─────────┴────────────────────┴──────────┴──────────┴──────┴───────────┘
Once the function works, .save reports/exploration.js stores the session and you have the code ready to paste into src/.
Ctrl+Dfinishes,Ctrl+Ccancels. Mixing them up loses the whole block. On Windows, ifCtrl+Ddoes not respond, tryCtrl+Zfollowed byEnter.
- Running One-Off Code Without the REPL:
node -e and node -p
node -e and node -pSometimes you only want an answer, not an interactive session. Node accepts code straight from the command line.
| Option | Meaning | Prints the result |
|---|---|---|
node -e "code" |
evaluate: runs the code | No (use console.log) |
node -p "code" |
print: runs it and prints the value | Yes, automatically |
# -e: you have to print explicitly
node -e "console.log(2 + 2)"
# 4
# -p: prints the value of the expression
node -p "2 + 2"
# 4
# Check the version from a deployment script
node -p "process.version"
# v24.5.0
# Check whether a package is installed and which version it is
node -p "require('express/package.json').version"A very practical case: processing a JSON file from the terminal without installing any extra tooling.
# How many events are in the seed file
node -p "require('./data/events.json').length"
# Event titles, one per line
node -e "require('./data/events.json').forEach(e => console.log(e.title))"Node knows how to read a .json with require and hand it back already converted into an object. This trick will solve a lot of quick checks for you from Module 3 onwards, when the file data/events.json becomes the real source of the catalog.
You can also feed the REPL through a pipe, although in that case you will not see the > prompt:
- Quirks: Promises, Top-Level
await and Other Surprises
await and Other SurprisesPromises and await
Node's REPL supports top-level await, something you cannot do in a CommonJS .js file. That makes it an excellent test bench for asynchronous code (the subject of Module 2).
> const fs = require('node:fs/promises')
undefined
> const text = await fs.readFile('src/catalog-data.js', 'utf8')
undefined
> text.length
1828If you do not use await, the REPL shows you the promise, not its value:
Shortly afterwards the REPL prints the resolved result on its own, which can look like it "appeared out of nowhere". Do not be alarmed: that is the REPL reporting that the promise settled.
Other quirks worth knowing
| Situation | What happens | Why |
|---|---|---|
{ a: 1 } returns 1 |
The REPL reads {} as a block, not as an object |
Wrap it in parentheses: ({ a: 1 }) |
let x = 1 twice raises an error |
Redeclaration in the same scope | Use var, or .clear, or change the name |
A long array is truncated with ... 73 more items |
The inspector's printing limit | console.dir(arr, { maxArrayLength: null }) |
Deep objects show [Object] |
Default inspection depth: 2 | console.dir(obj, { depth: null }) |
The REPL cannot see the variables of a file loaded with require |
require isolates the module |
Use .load to explore |
| An error does not close the REPL | Errors are caught and displayed | That is deliberate: you can carry on working |
Try the first one yourself:
> { title: 'Concierto de Otono' }
'Concierto de Otono'
> ({ title: 'Concierto de Otono' })
{ title: 'Concierto de Otono' }In the first case, JavaScript reads { as the start of a block and title: as a label; the value of the block is its last expression. With parentheses, you force it to be read as an object literal.
- When to Use the REPL and When Not To
The REPL is a tool for exploring, not for building. This table sums up the right choice:
| Need | Right tool |
|---|---|
| Checking what an expression returns | The REPL |
| Exploring the shape of some unfamiliar data | The REPL (.load + console.dir) |
| Trying out a transformation before writing it | The REPL or .editor |
| Looking up a module's API | The REPL + Tab |
| A one-off check from a shell script | node -p |
| Code that has to be repeated or version-controlled | A file in src/ |
| Logic longer than 30 lines | A file, even if you prototyped it in the REPL |
| Understanding why a complex program fails at a specific point | The debugger (Module 9) |
| Guaranteeing that something still works tomorrow | Automated tests (Module 9) |
The rule is simple: if you are going to need the result more than once, it does not belong in the REPL. Prototype in the REPL, save with .save, refine in a file.
And about the debugger: the REPL tells you what an isolated expression does; the debugger lets you stop a running program at any line you like and inspect all of its variables at that instant. They complement each other, they are not alternatives.
Common Mistakes and Tips
Mistake 1: being alarmed by the undefined after every declaration.
It is the value of the expression, not a failure. const x = 5 produces no value.
Mistake 2: typing { key: value } expecting an object.
The REPL reads it as a block. Wrap it in parentheses.
Mistake 3: getting stuck at the ... prompt.
You have left a brace, a parenthesis or a quote unclosed. Get out with .break or Ctrl+C.
Mistake 4: confusing .load with require.
.load evaluates the text in your session (you see every variable). require returns only what was exported.
Mistake 5: using .clear by accident.
It wipes every variable in the session. If you have invested time loading and transforming data, run .save first.
Mistake 6: sorting with sort and ruining the original array.
sort, reverse, splice, push and pop all mutate the array. Copy it with [...array] before sorting.
Tip 1: use _ freely. Chaining _ is the fastest way to refine a calculation step by step.
Tip 2: .save when an exploration has been productive. Saving the session into reports/ spares you from reconstructing the reasoning tomorrow.
Tip 3: Tab is your documentation. Before searching the internet for which methods path has, type path. and press Tab twice.
Tip 4: keep a REPL open in a terminal tab. With the catalog loaded, answering a question takes seconds.
Exercises
Exercise 1: a guided exploration of the catalog
Open the REPL, load src/catalog-data.js with .load and answer these questions using a single expression each time. Write down the command and the result.
- How many sessions are there in the catalog in total?
- What is the average ticket price, in euros?
- Which events have more than two sessions?
- How many tickets remain unsold across the whole catalog?
- Which is the most expensive session, and which event does it belong to?
Exercise 2: a function in editor mode
Using .editor, write a function sessionsPerMonth(events) that returns an object where each key is the month in YYYY-MM format and the value is the number of sessions scheduled that month. Try it out with the catalog and show the result with console.table. Then save the session to reports/exploration-months.js with .save.
Hint: session.dateTime is an ISO string such as '2026-10-03T20:00:00', so the month can be extracted with slice(0, 7).
Exercise 3: checks from the terminal
Without opening the REPL, write the node -e or node -p commands that solve the following:
- Print the major version of the installed Node (just the number, for example
24). - Print how many milliseconds are left from now until the
Concierto de Otono(2026-10-03T20:00:00). - Convert
4200cents into the string'42.00'. - Check whether the
reportsfolder exists in the project (printtrueorfalse).
Solutions
Solution 1
> .load src/catalog-data.js # 1. Total sessions > catalog.reduce((total, e) => total + e.sessions.length, 0) 7 # 2. Average price in euros > catalog.flatMap(e => e.sessions).reduce((s, x, i, a) => s + x.priceCents / a.length, 0) / 100 25.428571428571427
A more readable alternative, in two steps with _:
> catalog.flatMap(e => e.sessions).map(s => s.priceCents) [ 2500, 2200, 1800, 1800, 1500, 3800, 4200 ] > _.reduce((a, b) => a + b, 0) / _.length / 100 25.428571428571427
(17,800 cents across 7 sessions = 2,542.86 cents, that is 25.43 EUR.)
# 3. Events with more than two sessions
> catalog.filter(e => e.sessions.length > 2).map(e => e.title)
[ 'Noche de Monologos' ]
# 4. Unsold tickets
> catalog.flatMap(e => e.sessions).reduce((t, s) => t + (s.capacity - s.sold), 0)
1189
# 5. Most expensive session and its event
> catalog.flatMap(e => e.sessions.map(s => ({ ...s, event: e.title })))
.sort((a, b) => b.priceCents - a.priceCents)[0]
{ id: 'ses-003-2', ..., priceCents: 4200, event: 'Festival de Jazz de Primavera' }Here sort on the result of flatMap is safe: that array is new, it is not the original.
Solution 2
> .editor
function sessionsPerMonth(events) {
const counts = {};
for (const event of events) {
for (const session of event.sessions) {
// '2026-10-03T20:00:00'.slice(0, 7) === '2026-10'
const month = session.dateTime.slice(0, 7);
counts[month] = (counts[month] ?? 0) + 1;
}
}
return counts;
}Ctrl+D and try it out:
> sessionsPerMonth(catalog)
{ '2026-10': 5, '2027-04': 2 }
> console.table(sessionsPerMonth(catalog))
┌─────────┬────────┐
│ (index) │ Values │
├─────────┼────────┤
│ 2026-10 │ 5 │
│ 2027-04 │ 2 │
└─────────┴────────┘
> .save reports/exploration-months.js
Session saved to: reports/exploration-months.jsBear in mind that .save stores the whole session, including the lines that failed. Review the file before reusing it.
Solution 3
# 1. Node major version
node -p "process.versions.node.split('.')[0]"
# 24
# 2. Milliseconds until the Concierto de Otono
node -p "new Date('2026-10-03T20:00:00') - new Date()"
# 4483200000 (varies depending on when you run it)
# 3. Cents to a string with two decimals
node -p "(4200 / 100).toFixed(2)"
# 42.00
# 4. Check whether the reports folder exists
node -p "require('node:fs').existsSync('reports')"
# trueIn point 2, subtracting two Date objects automatically converts them to milliseconds since the epoch and returns the difference. If you prefer days:
Conclusion
The REPL is Node.js's laboratory: an environment where trying an idea costs nothing. You have learned to start it with node, to interpret the undefined after declarations, to chain calculations with _, to move around with Tab and the history, and to handle the dot commands — .help, .editor, .save, .load, .break, .clear, .exit.
You have applied it to Escena Viva by creating src/catalog-data.js and loading it with .load to explore live: flattening sessions with flatMap, calculating accumulated revenue with reduce, finding the most expensive session with sort, or discovering that there are 1,189 tickets still to sell. You have also seen node -e and node -p for checks from the terminal, and the quirks that trip people up at first: object literals that need parentheses, pending promises and top-level await.
And above all you are clear about the boundary: the REPL is for exploring; whatever has to be repeated goes into a file, and whatever has to be guaranteed goes into a test.
Along the way, some modern JavaScript tools slipped in almost by stealth: flatMap, the spread operator ..., nullish coalescing ??, arrow functions and destructuring. In the next lesson, Modern JavaScript for Node.js, we will study them one by one and without rushing, always while solving a real problem in the Escena Viva catalog. It is the refresher that will underpin every line of code you write from here to the end of the course.
Node.js Course: From Beginner to Advanced
Module 1: Introduction to Node.js
- What Is Node.js?
- Installing and Setting Up the Environment
- Your First Node.js Program
- The Node.js REPL
- Modern JavaScript for Node.js
- The Course Project: the Escena Viva Platform
Module 2: Core Concepts
- Node.js Architecture
- The Event Loop
- Callbacks and Asynchronous Programming
- Promises and async/await
- Events and EventEmitter
- CommonJS Modules and require()
- ES Modules and Interoperability
Module 3: File System and I/O
- Reading and Writing Files
- The fs Module in Depth
- Cross-Platform Paths with the path Module
- Working with Streams
- Transform Streams and pipeline
- Buffers and Binary Data
Module 4: HTTP and Web Servers
- Creating a Simple HTTP Server
- Handling Requests and Responses
- Manual Routing
- Serving Static Files
- Receiving Data: Request Bodies and JSON
- Consuming External APIs from Node.js
Module 5: NPM and Package Management
- Introduction to NPM and package.json
- Installing and Using Packages
- Semantic Versioning and package-lock
- npm Scripts and Project Automation
- Creating and Publishing Packages
- Dependency Security and Maintenance
Module 6: The Express.js Framework
- Introduction to Express.js
- Setting Up an Express Application
- Routing in Express
- Middleware
- Essential Third-Party Middleware
- Input Data Validation
- Error Handling
Module 7: Databases and ORMs
- Introduction to Databases
- Using MongoDB with Mongoose
- CRUD Operations
- Relationships, Population and Advanced Queries
- Using SQL Databases with Sequelize
- Migrations, Transactions and Seed Data
Module 8: Authentication and Authorization
- Introduction to Authentication
- User Registration and Password Hashing
- Sessions and Cookies with Passport.js
- Authentication with JWT
- Role-Based Access Control
- API Security Best Practices
Module 9: Testing and Debugging
- Introduction to Testing
- Unit Testing with Mocha and Chai
- Test Doubles with Sinon
- Integration Testing
- Coverage and Test Automation
- Debugging Node.js Applications
Module 10: Advanced Topics
- The Cluster Module
- Worker Threads
- Caching and Job Queues with Redis
- Performance Optimization
- Building RESTful APIs
- GraphQL with Node.js
Module 11: Deployment and DevOps
- Configuration and Environment Variables
- Logging and Monitoring in Production
- Using PM2 for Process Management
- Packaging with Docker
- Deploying to Heroku and Other PaaS
- Continuous Integration and Deployment
