WPROWADZENIE — JAK NARODZIŁ SIĘ NODE.JS?
Wyobraź sobie świat w 2009 roku:
- JavaScript działa tylko w przeglądarce.
- Backend to PHP, Java, Python — każdy request blokuje serwer.
- Aplikacje są wolne, toporne, nie skalują się.
- Programiści muszą znać dwa różne światy: JS na froncie, inny język na backendzie.
I wtedy pojawia się Ryan Dahl — młody programista, który patrzy na to wszystko i mówi:
„Dlaczego serwery muszą się blokować? Dlaczego JavaScript nie może działać na serwerze? Dlaczego nie możemy mieć jednego języka na frontend i backend?”
Ryan bierze silnik V8 z Google Chrome, łączy go z biblioteką libuv (asynchroniczne I/O) i tworzy:
Node.js — rewolucja w programowaniu webowym.

To nie jest „kolejny język”. To jest nowy sposób myślenia o programowaniu.
Czym jest Node.js?
Node.js to:
- silnik V8 (kompiluje JS do kodu maszynowego)
- Event Loop (dyrygent orkiestry zadań)
- non‑blocking I/O (nic nie blokuje programu)
- NPM (największy ekosystem paczek na świecie)
- środowisko uruchomieniowe JS poza przeglądarką
Node.js potrafi obsłużyć dziesiątki tysięcy połączeń jednocześnie, podczas gdy klasyczne serwery blokujące obsługują jedno połączenie na raz.
Event Loop — serce Node.js
Najważniejszy mechanizm, który musisz zrozumieć!
Event Loop to serce Node.js. To on decyduje, kiedy i w jakiej kolejności wykonywane są zadania.
REPL to skrót od Read-Eval-Print Loop (w tłumaczeniu: pętla Czytaj-Wykonaj-Wypisz). Jest to prosty, interaktywny program komputerowy, który działa w pętli i pozwala na natychmiastowe testowanie kodu.
Działa to w czterech powtarzających się krokach:
- Read (Czytaj): Program pobiera kod, który wpiszesz z klawiatury.
- Eval (Wykonaj): Komputer przetwarza i uruchamia ten kod.
- Print (Wypisz): Na ekranie od razu pojawia się wynik działania kodu.
- Loop (Pętla): Program wraca do początku i czeka na Twoją kolejną instrukcję.
Gdzie to znajdziesz?
- W przeglądarce: Gdy wciśniesz klawisz
F12w Chrome lub Firefox i wejdziesz w zakładkę Konsola (Console), to co tam wpisujesz, to właśnie REPL dla JavaScriptu. - W terminalu: Jeśli masz zainstalowany Node.js, wpisz w swoim terminalu samo słowo
node. Uruchomi się konsola REPL, gdzie możesz pisać i testować czysty JavaScript bez tworzenia jakichkolwiek plików. Aby opuścić konsolę można wpisać .exit lub Ctrl+D lub dwukrotnie wcisnąć ctrl+c
To idealne narzędzie do szybkiej nauki i sprawdzania, jak działają konkretne funkcje czy operacje matematyczne.
Wyobraź sobie:
Kuchnia w restauracji
- Kelner przyjmuje zamówienie (kod synchroniczny).
- Przekazuje je do kuchni (zadanie asynchroniczne).
- Wraca do obsługi innych klientów (Event Loop).
- Gdy danie jest gotowe, kuchnia daje sygnał (callback).
- Kelner dostarcza je do stolika (wykonanie callbacku).
Kelner nie stoi bezczynnie. Node.js nie stoi bezczynnie.

Przykład działania Event Loop
console.log("Start");
setTimeout(() => {
console.log("Timeout");
}, 0);
Promise.resolve().then(() => {
console.log("Promise");
});
console.log("Koniec");
Co się dzieje krok po kroku:
console.log("Start");- kod synchroniczny, wykonuje się od razu, wypisuje „Start”.
setTimeout(() => { console.log("Timeout"); }, 0);- rejestrujesz zadanie asynchroniczne (callback),
- funkcja trafia do kolejki callbacków (callback queue),
- nie wykonuje się od razu.
Promise.resolve().then(() => { console.log("Promise"); });- tworzysz promisa, który jest od razu spełniony,
- funkcja w
thentrafia do kolejki microtasks (microtask queue), - też nie wykonuje się od razu.
console.log("Koniec");- kod synchroniczny, wykonuje się od razu, wypisuje „Koniec”.
- Event Loop kończy wykonywanie kodu synchronicznego. Teraz:
- najpierw wykonuje microtasks →
Promise, - potem wykonuje callback queue →
Timeout.
- najpierw wykonuje microtasks →
Wynik:
Start
Koniec
Promise
Timeout
Dlaczego?
- Kod synchroniczny → Start, Koniec
- Microtasks → Promise
- Callback queue → Timeout
Instalacja Node.js — krok po kroku
- Wejdź na https://nodejs.org
- Pobierz wersję LTS
- Zainstaluj
- Sprawdź wersję:
node -v
npm -v
Jeśli widzisz numery wersji — Node.js i NPM działają.
NPM — największy ekosystem paczek na świecie
NPM (Node Package Manager) to:
- menedżer pakietów,
- repozytorium bibliotek,
- narzędzie do automatyzacji,
- system skryptów.
Przykładowe komendy:
npm install express
npm install nodemon --save-dev
npm install mysql2
npm install bcrypt
npm install jsonwebtoken
express— framework do tworzenia API,nodemon— automatyczne restartowanie serwera po zmianie pliku,mysql2— obsługa bazy MySQL,bcrypt— hashowanie haseł,jsonwebtoken— tokeny JWT.
Inicjalizacja projektu — npm init i plik package.json
1. Po co w ogóle jest „inicjalizacja projektu”?
Kiedy zaczynasz pracę nad projektem w Node.js, nie wystarczy mieć jeden plik app.js. Projekt potrzebuje:
- informacji o sobie (nazwa, wersja),
- listy bibliotek, których używa (dependencies),
- skryptów, które można uruchamiać (
npm start,npm run dev), - konfiguracji, którą rozumie NPM.
To wszystko trzyma w jednym miejscu plik package.json. Bez niego NPM „nie wie”, że folder jest projektem, nie wie, jakie paczki są potrzebne, nie wie, jakie skrypty ma uruchamiać.
2. Jak zainicjalizować projekt?
Krok po kroku:
- Tworzysz nowy folder, np.
my-app. - Wchodzisz do niego w terminalu:
cd my-app
- Uruchamiasz:
npm init -y
Co się dzieje?
npm init— mówi NPM: „utwórz plikpackage.jsondla tego projektu”.-y— oznacza „użyj domyślnych wartości, nie zadawaj mi pytań”.
Po tej komendzie w folderze pojawia się plik:
my-app/
package.json
3. Co jest w package.json? Rozpiska linia po linii
Przykładowa zawartość:
{
"name": "my-app",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Wyjaśnienie:
"name": "my-app"Nazwa projektu. Używana np. przy publikacji paczki w NPM (u Ciebie głównie informacyjnie)."version": "1.0.0"Wersja projektu. Formatmajor.minor.patch(np. 1.0.0, 1.1.0, 1.1.1). Przydaje się przy wersjonowaniu i publikacji."description": ""Krótki opis projektu. Możesz tu wpisać np."Simple Node.js server"."main": "app.js"Główny plik projektu (wejście). Niektóre narzędzia używają tego pola, żeby wiedzieć, który plik uruchomić jako pierwszy."scripts": { "start": "node app.js" }To jest bardzo ważne. Definiujesz tu komendy, które możesz uruchamiać przeznpm run ....
W tym przykładzie:"start": "node app.js"oznacza, że gdy wpiszesz w terminalu: npm start NPM uruchomi komendę node app.js, czyli odpali Twój plikapp.jsw Node.js.
"keywords": []Słowa kluczowe (np."node", "server"). Przydaje się przy publikacji paczki, u Ciebie może zostać puste."author": ""Autor projektu (np."Kama Kaczmarek")."license": "ISC"Licencja projektu (np. ISC, MIT). Na razie możesz zostawić domyślną.
4. Co się dzieje, gdy instalujesz paczki?
Załóżmy, że instalujesz Express:
npm install express
Po tej komendzie:
- Tworzy się folder
node_modules— tam lądują wszystkie zainstalowane paczki. - W
package.jsonpojawia się sekcjadependencies:
"dependencies": {
"express": "^4.19.2"
}
Co to znaczy?
"express"— nazwa paczki,"^4.19.2"— wersja (z^, czyli „zgodna z wersją 4.x.x”).
Dzięki temu:
- gdy ktoś inny sklonuje Twój projekt,
- wystarczy, że uruchomi
npm install, - NPM przeczyta
package.json, - zainstaluje wszystkie paczki z
dependencies.
Nie trzeba kopiować node_modules — wystarczy package.json.
5. dependencies vs devDependencies
Masz dwa typy zależności:
"dependencies"— paczki potrzebne w czasie działania aplikacji (np.express,mysql2)."devDependencies"— paczki potrzebne tylko w czasie developmentu (np.nodemon,eslint).
Przykład:
npm install nodemon --save-dev
Doda:
"devDependencies": {
"nodemon": "^3.0.0"
}
Dlaczego to ważne?
- na produkcji nie potrzebujesz
nodemon, - ale potrzebujesz
express, - rozdzielenie tych paczek pozwala budować lżejsze środowisko produkcyjne.
6. Jak wygląda typowy workflow z package.json?
- Tworzysz projekt:
npm init -y
- Instalujesz paczki:
npm install express
npm install nodemon --save-dev
- Dodajesz skrypty:
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
}
- Uruchamiasz:
- w trybie produkcyjnym:
npm start
- w trybie developerskim (auto‑restart po zmianach):
npm run dev
Pierwszy skrypt Node.js
Plik: app.js
console.log("Hello from Node.js!");
Uruchom:
node app.js
W terminalu zobaczysz:
Hello from Node.js!
Pierwszy serwer HTTP — Twój pierwszy backend
Do tej pory JavaScript działał u Ciebie tylko w przeglądarce — w React, w konsoli, w prostych skryptach. Ale prawdziwe aplikacje webowe potrzebują backendu, czyli programu, który:
- nasłuchuje na porcie,
- odbiera żądania od przeglądarki,
- przetwarza dane,
- zwraca odpowiedź (HTML, JSON, pliki, statusy),
- komunikuje się z bazą danych,
- obsługuje logikę biznesową.
W klasycznych technologiach backendowych (PHP, Python, Java) serwer jest tworzony przez framework. W Node.js możesz stworzyć serwer od zera, bez żadnych bibliotek — tylko za pomocą modułu http.
To pozwala Ci zrozumieć:
- jak działa komunikacja klient → serwer,
- czym jest żądanie (
req) i odpowiedź (res), - jak działa routing,
- jak zwracać różne typy danych,
- jak działa port i nasłuchiwanie.
To jest fundament, na którym później zbudujesz Express, API REST, autoryzację, upload plików, bazy danych itd.
Jak działa serwer HTTP w Node.js?
Serwer HTTP to program, który:
- nasłuchuje na porcie (np. 3000),
- czeka na żądania od przeglądarki,
- odbiera żądanie (np. GET /),
- tworzy odpowiedź (np. HTML, JSON),
- wysyła odpowiedź do klienta.
W Node.js serwer działa w jednym wątku, ale dzięki Event Loop może obsługiwać tysiące połączeń jednocześnie.
const http = require("http");
const server = http.createServer((req, res) => {
res.writeHead(200, {"Content-Type": "text/plain; charset=utf-8"});
res.end("Witaj w Node.js!");
});
server.listen(3000);
Wyjaśnienie linia po linii:
const http = require("http");- importujesz moduł
httpwbudowany w Node.js, - ten moduł pozwala tworzyć serwery HTTP.
- importujesz moduł
const server = http.createServer((req, res) => { ... });- tworzysz serwer,
req— obiekt żądania (informacje o tym, co przysłał klient),res— obiekt odpowiedzi (to, co wyślesz do klienta).
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });- ustawiasz status odpowiedzi na
200(OK), - ustawiasz nagłówek
Content-Typenatext/plain(zwykły tekst) i dodajemy dla polskich znaków diakrytycznychcharset=utf-8.
- ustawiasz status odpowiedzi na
res.end("Witaj w Node.js!");- kończysz odpowiedź,
- wysyłasz tekst do klienta.
server.listen(3000);- serwer nasłuchuje na porcie
3000, - możesz wejść w przeglądarce na
http://localhost:3000.
- serwer nasłuchuje na porcie
Właśnie stworzyłeś backend, który działa jak prawdziwy serwer.
Zwracanie HTML i JSON — krok po kroku
Serwer HTTP może zwracać różne typy danych. Najczęściej:
- HTML — gdy chcesz wyświetlić stronę,
- JSON — gdy tworzysz API.
HTML:
res.writeHead(200, {"Content-Type": "text/html; charset=utf-8"});
res.end("<h1>Witaj!</h1>");
Content-Type: text/html— przeglądarka wie, że to HTML.res.end("<h1>Witaj!</h1>");— wysyłasz prosty dokument HTML.- Przeglądarka wyświetli nagłówek
<h1>.
JSON:
res.writeHead(200, {"Content-Type": "application/json; charset=utf-8"});
res.end(JSON.stringify({status: "ok"}));
Content-Type: application/json— klient wie, że to JSON.JSON.stringify(...)— zamienia obiekt JS na tekst JSON.res.end(...)— wysyłasz JSON do klienta.
To jest fundament API — backend zwraca JSON, frontend go odbiera.
Node.js vs inne technologie
| Technologia | Model pracy | Zalety | Wady |
|---|---|---|---|
| Node.js | Event Loop | szybkość, skalowalność, JS wszędzie | wymaga zrozumienia asynchroniczności |
| PHP | blokujący | prosty start | wolniejszy, każdy request osobno |
| Python | blokujący (domyślnie) | ogromny ekosystem | GIL ogranicza wątki |
| Java | wielowątkowy | stabilność, enterprise | cięższy start |
Mini‑projekt: Twój pierwszy mini‑backend
W tym mini‑projekcie tworzysz pierwszy backend, który:
- obsługuje trzy różne ścieżki,
- zwraca trzy różne typy odpowiedzi,
- pokazuje jak działa routing,
- pokazuje jak działa protokół HTTP,
- pokazuje jak działa serwer bez frameworków,
- pokazuje jak działa komunikacja klient → serwer → klient.
To jest pierwszy backend, który zachowuje się jak prawdziwa aplikacja:
- reaguje na różne adresy,
- zwraca różne dane,
- obsługuje błędy,
- działa na porcie,
- komunikuje się z przeglądarką.
To jest fundament pod:
- Express,
- API REST,
- autoryzację,
- bazy danych,
- upload plików,
- pełne aplikacje backendowe.
Architektura mini‑projektu — co dokładnie zbudujesz?
Twój serwer będzie obsługiwał trzy ścieżki:
| Ścieżka | Typ odpowiedzi | Co zwraca | Po co? |
|---|---|---|---|
/ | HTML | Stronę główną | pokazuje zwracanie HTML |
/api/products | JSON | listę produktów | pokazuje API |
/info | tekst | informację o serwerze | pokazuje zwykły tekst |
| inne | tekst + status 404 | błąd | pokazuje obsługę błędów |
To jest pełny routing, a nie tylko „tekst / HTML / JSON”.
Pełny kod mini‑projektu
Plik: server.js
const http = require("http");
// --- 1. Lista produktów (dane przykładowe) ---
const products = [
{ id: 1, name: "Kawa", price: 19.99 },
{ id: 2, name: "Herbata", price: 12.50 },
{ id: 3, name: "Czekolada", price: 8.99 }
];
// --- 2. Tworzenie serwera ---
const server = http.createServer((req, res) => {
// --- 3. Routing: strona główna ---
if (req.url === "/") {
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
res.end(`
<h1>Witaj w moim pierwszym backendzie!</h1>
<p>Przejdź do <a href="/api/products">/api/products</a>, aby zobaczyć dane JSON.</p>
<p>Przejdź do <a href="/info">/info</a>, aby zobaczyć informacje o serwerze.</p>
`);
return;
}
// --- 4. Routing: API zwracające JSON ---
if (req.url === "/api/products") {
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
res.end(JSON.stringify(products));
return;
}
// --- 5. Routing: zwykły tekst ---
if (req.url === "/info") {
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
res.end("To jest prosty backend napisany w Node.js.");
return;
}
// --- 6. Routing: 404 dla innych ścieżek ---
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
res.end("404 — Nie znaleziono");
});
// --- 7. Nasłuchiwanie na porcie ---
server.listen(3000);
Wyjaśnienie linia po linii
1. Import modułu HTTP
const http = require("http");
- Ładujesz moduł
httpwbudowany w Node.js. - Ten moduł pozwala tworzyć serwery HTTP bez żadnych bibliotek.
- To jest najniższy poziom backendu — „goły” serwer.
2. Dane przykładowe — lista produktów
const products = [
{ id: 1, name: "Kawa", price: 19.99 },
{ id: 2, name: "Herbata", price: 12.50 },
{ id: 3, name: "Czekolada", price: 8.99 }
];
- Tworzysz tablicę obiektów.
- To jest „udawana baza danych”.
- Dzięki temu
/api/productszwraca prawdziwe dane JSON.
3. Tworzenie serwera
const server = http.createServer((req, res) => {
- Tworzysz serwer HTTP.
req— żądanie od klienta.res— odpowiedź, którą wyślesz.
4. Routing — strona główna
if (req.url === "/") {
- Sprawdzasz, czy użytkownik wszedł na
/.
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
- Ustawiasz status 200 OK.
- Ustawiasz typ odpowiedzi na HTML.
res.end(`
<h1>Witaj w moim pierwszym backendzie!</h1>
<p>Przejdź do <a href="/api/products">/api/products</a>, aby zobaczyć dane JSON.</p>
<p>Przejdź do <a href="/info">/info</a>, aby zobaczyć informacje o serwerze.</p>
`);
- Wysyłasz HTML.
- Widzisz, że backend może zwracać prawdziwe strony.
5. Routing — API zwracające JSON
if (req.url === "/api/products") {
- Sprawdzasz ścieżkę
/api/products.
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
- Ustawiasz typ odpowiedzi na JSON.
res.end(JSON.stringify(products));
- Zamieniasz tablicę obiektów na JSON.
- Wysyłasz ją do klienta.
To jest prawdziwe API.
6. Routing — zwykły tekst
if (req.url === "/info") {
- Sprawdzasz ścieżkę
/info.
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
res.end("To jest prosty backend napisany w Node.js.");
- Wysyłasz zwykły tekst.
7. Routing — 404
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
res.end("404 — Nie znaleziono");
- Każda inna ścieżka → błąd 404.
- To jest podstawowa obsługa błędów.
8. Nasłuchiwanie na porcie
server.listen(3000);
- Serwer działa na porcie 3000.
- Wchodzisz w przeglądarce:
Kod
http://localhost:3000
5. Ćwiczenia praktyczne
Ćwiczenie 1 — Event Loop (analiza kolejności)
Kod:
console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C"));
console.log("D");
Oczekiwany wynik:
A
D
C
B
Dlaczego?
- synchroniczne: A, D
- microtasks: C
- callback queue: B
Ćwiczenie 2 — Twój pierwszy projekt Node.js
Zadanie:
- Utwórz folder projektu.
- Zainicjalizuj
package.json:
npm init -y
- Dodaj skrypt:
"scripts": {
"start": "node app.js"
}
- Utwórz plik
app.js:
console.log("Pierwszy projekt Node.js!");
- Uruchom:
npm start
Ćwiczenie 3 — Serwer HTTP
Zadanie:
Stwórz serwer, który zwraca:
- tekst na
/text, - HTML na
/html, - JSON na
/json.
Co dalej?
Po tym module będziesz umieć:
- pracować z modułami,
- używać
fsipath, - czytać i zapisywać pliki,
- pracować ze strumieniami,
- tworzyć API w Express,
- łączyć Node.js z bazą danych,
- tworzyć pełne backendy.
Kryteria sukcesu
- Rozumiem Event Loop
- Umiem zainstalować Node.js
- Umiem stworzyć projekt Node.js
- Umiem uruchomić skrypt
- Umiem stworzyć serwer HTTP
- Umiem zwrócić HTML i JSON