
Node.js 설치부터 첫 서버까지 (1/5)

JavaScript 다음 스텝 - Part 1: JavaScript가 브라우저를 벗어나는 순간
JavaScript 기본 문법을 배우고 나면 한 가지 의문이 생깁니다. "변수, 함수, 객체, 배열... 다 배웠는데, 이걸로 대체 뭘 만들지?" 브라우저 콘솔에서 console.log('Hello')를 찍어보는 것만으로는 뭔가 만들었다는 실감이 나지 않습니다.
IT 강의를 오래 해오면서 이 시점에서 멈추는 분들을 많이 봤습니다. 문법은 아는데 "다음 단계"가 뭔지 모르겠다는 겁니다. 그 다음 단계가 바로 Node.js입니다. JavaScript를 브라우저 밖으로 꺼내서, 서버를 만들고, 파일을 다루고, 데이터베이스에 접근하는 것. 브라우저 안에 갇혀 있던 JavaScript가 "범용 프로그래밍 언어"로 확장되는 순간입니다.
이 글은 "JavaScript 다음 스텝" 시리즈의 첫 번째 편입니다. 총 5편에 걸쳐 Node.js와 Express로 메모장 웹 앱을 만듭니다. 이번 편에서는 Node.js를 설치하고, 터미널에서 JavaScript 파일을 실행하고, Express로 "Hello World" 서버를 띄워서 브라우저에서 확인하는 것까지 진행합니다. 이 글을 끝까지 따라하면, 내 컴퓨터에서 웹 서버가 돌아가는 것을 직접 눈으로 확인할 수 있습니다.
Node.js란 무엇인가
JavaScript는 원래 브라우저 전용 언어였습니다. 1995년 넷스케이프 브라우저에서 웹페이지에 동작을 넣으려고 만들었는데, 이후 30년 가까이 "브라우저 안에서만" 동작했거든요.
Node.js가 이 제한을 깼습니다. 공식 사이트 설명에 따르면, Node.js는 "브라우저 밖에서 JavaScript를 실행할 수 있게 해주는 무료 오픈소스 런타임 환경"입니다. 런타임 환경이란 프로그래밍 언어를 실행하는 데 필요한 모든 것을 갖춘 환경을 뜻하는데요. 구체적으로는 Google Chrome에 내장된 V8 JavaScript 엔진을 가져다가 브라우저 없이도 돌아가게 만든 겁니다.
이게 왜 중요한지, 실질적인 차이를 보겠습니다.
브라우저에서 JavaScript를 실행하면 document, window 같은 객체를 사용할 수 있습니다. HTML 요소를 선택하고, 클릭 이벤트를 달고, 화면을 바꾸는 작업을 합니다. 하지만 파일을 읽거나 쓸 수는 없습니다. 보안상 브라우저가 막아두기 때문입니다. 사용자의 컴퓨터 파일에 마음대로 접근할 수 있는 웹사이트가 있다면 위험하겠죠.
Node.js에서 JavaScript를 실행하면 반대입니다. document나 window가 없죠. HTML이 없으니 당연합니다. 대신 파일을 읽고 쓸 수 있고, 네트워크 요청을 받을 수 있고, 운영체제 정보도 가져올 수 있습니다. 서버를 만들 수 있다는 뜻이죠.
정리하면 이렇습니다.
| 구분 | 브라우저 JavaScript | Node.js JavaScript |
|---|---|---|
| 실행 환경 | 브라우저 (Chrome, Firefox 등) | 터미널, 서버 |
| 할 수 있는 것 | DOM 조작, 화면 제어, 사용자 이벤트 | 파일 읽기/쓰기, 네트워크, 서버 |
| 할 수 없는 것 | 파일 접근, 서버 생성 | DOM 조작 (document, window 없음) |
| 주요 용도 | 웹페이지 동적 기능 | 서버, CLI 도구, 스크립트 |
같은 JavaScript인데 실행 환경에 따라 할 수 있는 일이 다릅니다. const, let, function, for, 배열 메서드 같은 기본 문법은 양쪽에서 동일하게 동작하고요. 차이가 나는 건 환경이 제공하는 기능입니다.
Node.js가 얼마나 널리 쓰이는지 수치로 보면, 2024년 Stack Overflow Developer Survey 기준 개발자의 40.8%가 Node.js를 사용합니다. 전 세계 630만 개 이상의 웹사이트가 Node.js 기반으로 운영되고 있고요(electroiq.com, 2025). 취업 시장에서도 백엔드 개발의 주요 선택지 중 하나입니다.
Node.js 설치하기
방법 1: 공식 사이트에서 직접 설치 (가장 간단)
가장 쉬운 방법은 공식 사이트에서 다운로드하는 것입니다.
- 브라우저에서 https://nodejs.org 에 접속합니다.
- 두 가지 버전이 보입니다. LTS와 Current입니다.
- LTS를 다운로드합니다.
LTS는 Long Term Support의 약자로, "오랫동안 안정적으로 지원하는 버전"이라는 뜻입니다. Node.js는 짝수 버전(22.x, 24.x, 26.x 등)이 LTS로 지정되며, 각 LTS 버전은 약 30개월간 지원됩니다. 공식 사이트에 접속하면 초록색 LTS 버튼이 보이는데, 그걸 다운로드하면 됩니다. Current 버전은 최신 기능이 먼저 추가되지만 안정성 검증이 덜 됐을 수 있거든요. 입문 단계에서는 LTS가 맞습니다. 회사에서도 프로덕션 서버에는 LTS만 쓰는 곳이 대부분이고요.
다운로드한 설치 파일을 실행하면 안내에 따라 Next를 누르면서 설치를 완료합니다. 별다른 옵션 변경 없이 기본값으로 진행하면 됩니다.
방법 2: nvm으로 설치 (권장)
nvm(Node Version Manager)은 여러 버전의 Node.js를 설치하고 전환할 수 있는 도구입니다. npm 공식 문서에서도 nvm을 통한 설치를 권장하고 있고요. 프로젝트마다 다른 Node.js 버전이 필요할 때 유용합니다. 입문 단계에서 반드시 필요하지는 않지만, 처음부터 nvm으로 설치해두면 나중에 따로 바꿀 필요가 없어서 편합니다.
맥/리눅스에서 nvm 설치:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
설치 후 터미널을 한 번 닫았다가 다시 열어야 합니다. 그래야 nvm 명령어가 동작합니다.
# 최신 LTS 버전 설치 nvm install --lts # 설치된 버전 확인 node --version
윈도우에서는 nvm-windows라는 별도 프로젝트를 사용합니다. https://github.com/coreybutler/nvm-windows 에서 설치 파일을 다운로드하면 됩니다. 사용법은 동일합니다.
설치 확인
어떤 방법으로 설치했든, 터미널(맥은 터미널, 윈도우는 명령 프롬프트 또는 PowerShell)을 열고 다음 두 명령어를 실행합니다.
node --version
v24.x.x
npm --version
10.x.x
버전 숫자가 출력되면 설치가 완료된 것입니다. node는 JavaScript 실행기이고, npm은 패키지 매니저(다른 사람이 만든 코드를 가져다 쓰는 도구)입니다. npm은 Node.js를 설치할 때 자동으로 함께 설치됩니다.
만약 "command not found"나 "'node'은(는) 내부 또는 외부 명령...이 아닙니다" 같은 메시지가 나온다면, 터미널을 닫고 다시 열어보세요. 설치 직후에는 환경 변수가 반영되지 않은 상태일 수 있습니다. 그래도 안 된다면 Node.js를 다시 설치해보는 것이 가장 빠릅니다.
터미널에서 JavaScript 실행하기
Node.js가 설치됐으니, 브라우저 없이 JavaScript를 실행해보겠습니다.
아무 폴더에서 hello.js라는 파일을 만듭니다. 메모장이든 VS Code든 어떤 텍스트 편집기를 써도 상관없습니다. 확장자가 .js이기만 하면 됩니다.
// hello.js console.log('안녕하세요, Node.js!');
이 파일을 저장하고, 터미널에서 해당 폴더로 이동한 다음 실행합니다.
node hello.js
안녕하세요, Node.js!
터미널에 텍스트가 출력됩니다. 브라우저를 열지 않았고, HTML 파일도 없습니다. 터미널에서 바로 JavaScript가 실행된 것입니다.
console.log()는 JavaScript 표준 문법입니다. 브라우저에서는 개발자도구 콘솔에 출력되고, Node.js에서는 터미널에 출력됩니다. 같은 코드가 환경에 따라 출력 위치만 다릅니다.
조금 더 복잡한 코드를 실행해보겠습니다. 변수, 함수, 객체를 사용하는 코드입니다.
// practice.js const name = '개발자'; const year = 2026; function greet(who) { return who + '님, ' + year + '년에 Node.js를 시작하셨군요!'; } const person = { name: name, skill: 'JavaScript' }; console.log(greet(person.name)); console.log('보유 스킬: ' + person.skill);
node practice.js
개발자님, 2026년에 Node.js를 시작하셨군요! 보유 스킬: JavaScript
const, function, 객체 리터럴({}) 모두 JavaScript 기본 문법 그대로입니다. Node.js에서 새로 배울 문법이 아니거든요. JavaScript 문법을 이미 알고 있다면 Node.js에서도 그대로 쓸 수 있습니다.
여기서 핵심은 이겁니다. Node.js는 새로운 언어가 아닙니다. JavaScript를 실행하는 새로운 "장소"입니다. 문법이 아니라 환경이 바뀐 것입니다.
npm과 package.json
실제 프로젝트를 시작해보겠습니다. 이 시리즈에서 만들 "메모장 앱"의 프로젝트 폴더를 만듭니다.
mkdir memo-app cd memo-app
mkdir은 폴더를 만드는 명령어이고, cd는 해당 폴더로 이동하는 명령어입니다.
이 폴더를 Node.js 프로젝트로 초기화합니다.
npm init -y
npm은 Node Package Manager의 약자입니다. 다른 사람이 만든 코드(패키지)를 가져다 쓸 수 있게 해주는 도구죠. npm init은 "이 폴더를 npm 프로젝트로 시작하겠다"는 뜻이고, -y는 "질문 없이 기본값으로 전부 예(yes)를 선택하겠다"는 옵션입니다.
실행하면 package.json이라는 파일이 하나 생깁니다. 열어보면 대략 이런 내용입니다. 필드 순서는 npm 버전에 따라 다를 수 있습니다. 내용이 같으면 정상입니다.
{ "name": "memo-app", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
package.json은 이 프로젝트의 "신분증" 같은 파일입니다. 프로젝트 이름, 버전, 설명이 적혀 있고, 이 프로젝트가 어떤 외부 패키지를 사용하는지도 여기에 기록됩니다. 지금은 외부 패키지를 하나도 설치하지 않았기 때문에 dependencies 항목이 없습니다.
각 필드를 간단히 보겠습니다.
name은 프로젝트 이름이고, 폴더 이름이 자동으로 들어갑니다. version은 버전 번호, main은 프로젝트의 시작 파일입니다. scripts는 자주 쓰는 명령어를 등록해두는 곳인데요. 예를 들어 "start": "node server.js"를 추가하면, npm start만 입력해도 node server.js가 실행됩니다. 이 부분은 나중에 활용하겠습니다.
지금 당장 모든 필드를 이해할 필요는 없습니다. "이 프로젝트가 뭘 쓰는지 기록하는 파일"이라는 것만 알면 됩니다.
Express 설치하기
Node.js만으로도 서버를 만들 수 있지만, 코드가 꽤 길고 복잡해집니다. Express는 Node.js 위에서 동작하는 웹 프레임워크로, 서버를 훨씬 간단하게 만들 수 있게 도와주죠. Node.js 생태계에서 가장 오래되고 가장 널리 쓰이는 프레임워크이기도 합니다. Fastify나 Hono 같은 더 빠른 프레임워크도 있지만(벤치마크상 Fastify는 Express보다 약 1.7배 빠릅니다), 학습 자료와 커뮤니티 규모에서 Express를 따라올 프레임워크는 아직 없습니다. 입문 단계에서는 Express로 시작하는 게 맞습니다.
memo-app 폴더 안에서 다음 명령어를 실행합니다.
npm install express
설치가 끝나면 두 가지가 생깁니다.
첫째, node_modules라는 폴더가 생깁니다. Express와 Express가 내부적으로 사용하는 모든 패키지가 이 폴더 안에 저장됩니다. 열어보면 폴더가 수십 개 들어있는데, 놀라지 않아도 됩니다. Express 하나를 설치했는데 왜 이렇게 많은가 하면, Express도 다른 패키지들을 가져다 쓰고, 그 패키지들도 또 다른 패키지를 쓰기 때문이거든요. 이걸 의존성(dependency)이라고 부릅니다. 이 폴더는 직접 건드릴 일이 없고, npm install이 알아서 관리합니다.
둘째, package-lock.json이라는 파일이 생깁니다. 이 파일은 설치된 모든 패키지의 정확한 버전을 기록합니다. "Express 5.0.1을 설치했고, Express가 쓰는 body-parser는 2.1.0 버전이고..." 하는 식으로 정밀하게 기록되는데요. 이 파일도 직접 수정할 일은 없습니다.
그리고 package.json을 다시 열어보면 dependencies 항목이 추가된 것을 확인할 수 있습니다.
{ "dependencies": { "express": "^5.0.1" } }
버전 숫자는 설치 시점에 따라 다를 수 있습니다. ^5.0.1이든 ^5.2.1이든, 앞자리가 5로 시작하면 정상입니다. ^ 기호는 "메이저 버전(5)은 유지하되, 마이너 버전과 패치 버전은 최신으로 설치해도 된다"는 뜻입니다.
"이 프로젝트는 Express 패키지를 사용한다"는 것이 기록된 것입니다.
정리하면, 프로젝트 폴더의 현재 구조는 다음과 같습니다.
memo-app/ node_modules/ <- 설치된 패키지들 (건드리지 않음) package.json <- 프로젝트 정보 + 의존성 목록 package-lock.json <- 정확한 버전 기록 (건드리지 않음)
첫 서버 띄우기
드디어 서버를 만들 차례입니다. memo-app 폴더 안에 server.js라는 파일을 만듭니다.
// server.js const express = require('express'); const app = express(); app.get('/', function(req, res) { res.send('안녕하세요! 메모 앱 서버가 동작 중입니다.'); }); app.listen(3000, function() { console.log('서버가 http://localhost:3000 에서 실행 중입니다'); });
이 코드가 이 글에서 가장 중요합니다. 8줄밖에 안 되지만, 초보자에게는 생소한 부분이 꽤 있습니다. 한 줄씩 뜯어보겠습니다.
const express = require('express');
const는 JavaScript 표준 문법으로, 값이 바뀌지 않는 변수를 선언합니다. JavaScript에서 변수를 선언하는 방법은 세 가지인데요. var는 오래된 방식이고, let은 값을 나중에 바꿀 수 있는 변수, const는 한 번 정한 값을 바꿀 수 없는 변수입니다. express라는 변수에 Express 패키지를 담을 것이고, 이 값은 바뀔 일이 없으니 const를 씁니다.
require('express')는 Node.js 전용 문법입니다. 브라우저 JavaScript에는 없는 함수죠. require()는 다른 파일이나 설치한 패키지의 코드를 가져오는 함수입니다. 여기서는 아까 npm install express로 설치한 Express 패키지를 가져옵니다.
브라우저에서 외부 코드를 가져올 때는 HTML의 <script src="파일.js">를 사용합니다. Node.js에는 HTML이 없으니 대신 require()를 사용하는 것입니다. 온라인에서 import express from 'express' 같은 다른 방식을 본 적이 있을 수 있는데, 이것과 require()의 차이는 뒤에서 별도로 다룹니다.
const app = express();
express()는 Express 패키지가 제공하는 함수입니다. 이 함수를 실행하면 Express 애플리케이션 객체가 만들어집니다. 이 app 객체에 "이 주소로 요청이 오면 이렇게 응답해라"는 규칙을 등록하게 됩니다.
app.get('/', function(req, res) { ... });
이 부분은 세 가지 요소로 구성되어 있습니다.
app.get()은 Express가 제공하는 메서드입니다. "GET 방식의 HTTP 요청이 오면 이 함수를 실행해라"라는 뜻이죠. HTTP GET은 "데이터를 달라"는 요청 방식입니다. 브라우저 주소창에 URL을 입력하고 엔터를 치면, 브라우저는 그 주소로 GET 요청을 보냅니다.
'/'는 URL 경로입니다. /는 루트 경로, 즉 웹사이트의 첫 페이지를 뜻합니다. http://localhost:3000/ 에 접속하면 이 함수가 실행됩니다.
function(req, res) { ... }는 콜백 함수입니다. 콜백 함수란 "특정 상황이 발생하면 대신 실행해달라고 등록해두는 함수"입니다. 여기서는 "누군가 / 주소로 GET 요청을 보내면 이 함수를 실행해라"라고 Express에 등록하는 거죠.
req와 res는 Express가 콜백 함수에 자동으로 넣어주는 매개변수입니다. req는 request(요청)의 줄임말로, 누가 어떤 요청을 보냈는지에 대한 정보가 들어있습니다. res는 response(응답)의 줄임말로, 요청한 사람에게 어떤 응답을 보낼지를 제어합니다.
여기서 화살표 함수(Arrow Function)라는 것도 소개합니다. 위 코드는 이렇게 쓸 수도 있습니다.
app.get('/', (req, res) => { res.send('안녕하세요! 메모 앱 서버가 동작 중입니다.'); });
위 코드처럼 콜백 함수로 사용할 때, function(req, res) { ... }와 (req, res) => { ... }는 동일하게 동작합니다. 화살표 함수는 JavaScript ES6에서 추가된 축약 문법입니다. 둘 사이에 미세한 차이(this 바인딩 방식)가 있지만, 지금 단계에서는 신경 쓰지 않아도 됩니다. 온라인에서 코드를 찾으면 화살표 함수로 된 것이 많으니 "이건 function의 축약형이구나"라고 알아두면 되고요. 이 시리즈에서는 읽기 편하도록 function 키워드를 사용하겠습니다.
res.send('안녕하세요! ...');
res.send()는 Express가 제공하는 메서드입니다. 요청을 보낸 사람(브라우저)에게 텍스트를 응답으로 보냅니다. 브라우저가 이 텍스트를 받아서 화면에 표시합니다.
app.listen(3000, function() { ... });
app.listen()은 Express가 제공하는 메서드입니다. 서버를 시작하고, 지정한 포트 번호에서 요청을 기다리기 시작하죠. 첫 번째 인자 3000은 포트 번호이고, 두 번째 인자는 서버가 정상적으로 시작된 후 실행되는 콜백 함수입니다.
이 마지막 줄이 실행되는 순간, 컴퓨터는 3000번 포트에서 들어오는 요청을 받을 준비를 합니다. 프로그램이 끝나지 않고 "계속 기다리는 상태"가 됩니다.
서버 실행하고 브라우저에서 확인하기
이제 실행합니다. 터미널에서 memo-app 폴더에 있는 상태에서 다음 명령어를 입력합니다.
node server.js
서버가 http://localhost:3000 에서 실행 중입니다
이 메시지가 나오면 서버가 실행된 것입니다. 터미널이 아무 입력도 받지 않는 "대기 상태"가 됩니다. 이 상태에서 터미널을 그대로 두고, 브라우저를 엽니다.
브라우저 주소창에 http://localhost:3000을 입력하고 엔터를 칩니다.
화면에 "안녕하세요! 메모 앱 서버가 동작 중입니다."라는 텍스트가 보입니다.
이것이 무슨 일이 벌어진 건지 단계별로 보겠습니다. 다음 그림은 터미널(서버)과 브라우저 사이에서 요청과 응답이 오가는 전체 흐름을 보여줍니다. 그림에서 Terminal은 서버가 실행되는 터미널 영역을, Browser는 사용자의 브라우저 영역을 나타냅니다.

node server.js를 실행하면, Node.js가server.js파일을 읽고 실행합니다.app.listen(3000, ...)이 실행되면서 컴퓨터의 3000번 포트에서 요청을 기다립니다.- 브라우저에
http://localhost:3000을 입력하면, 브라우저가 이 주소로 GET 요청을 보냅니다. - Express가
app.get('/', ...)에 등록된 함수를 실행합니다. res.send()가 텍스트를 브라우저에 보냅니다.- 브라우저가 받은 텍스트를 화면에 표시합니다.
내 컴퓨터에서 서버를 켜고, 내 컴퓨터의 브라우저에서 그 서버에 접속한 것입니다.
localhost와 포트 번호
http://localhost:3000에서 localhost는 "이 컴퓨터 자신"을 가리키는 특별한 주소입니다. IP 주소로는 127.0.0.1과 같죠. 인터넷에 연결된 다른 컴퓨터가 아니라, 지금 내가 쓰고 있는 바로 이 컴퓨터를 뜻합니다.
:3000은 포트 번호입니다. 한 컴퓨터에서 여러 서비스가 동시에 돌아갈 수 있잖아요. 웹 서버도 돌리고, 데이터베이스도 돌리고, 다른 앱도 돌릴 수 있습니다. 이때 각 서비스를 구분하기 위해 포트 번호를 사용합니다.
비유하면, localhost가 아파트 건물이라면 포트 번호는 호수(101호, 102호, 201호...)입니다. 같은 건물(컴퓨터)이지만, 3000호(포트 3000)에는 우리의 Express 서버가, 3306호(포트 3306)에는 MySQL 데이터베이스가 있는 식입니다. 다음 그림은 이 아파트 비유를 시각적으로 보여줍니다. 그림에서 Localhost는 내 컴퓨터를, Port는 각 서비스가 사용하는 문 번호를 의미합니다.

그림 하단의 공식처럼, http://localhost:3000은 "내 컴퓨터(localhost)의 3000번 포트(Port 3000)"를 뜻합니다. 80번 포트에는 HTTP 웹 서버가, 443번에는 HTTPS가, 3306번에는 MySQL이 자리 잡을 수 있고, 우리가 만든 Express 서버는 3000번 포트에서 요청을 기다리고 있는 것입니다.
개발 서버에는 관례적으로 3000번, 8080번 등을 씁니다. 특별한 이유는 없고 관례입니다. 1023번 이하의 포트는 시스템이 예약해둔 것이 많으므로(80번은 HTTP, 443번은 HTTPS 등), 개발할 때는 1024 이상의 번호를 사용합니다.
지금 상태에서는 내 컴퓨터에서만 이 서버에 접속할 수 있습니다. 같은 네트워크에 있는 다른 컴퓨터에서도 접속하게 하려면 추가 설정이 필요한데, 지금 단계에서는 신경 쓸 필요 없습니다.
서버 종료와 포트 충돌 해결
서버를 끄려면 터미널에서 Ctrl + C를 누릅니다. 맥에서도 윈도우에서도 동일합니다. Ctrl + C는 "현재 실행 중인 프로그램을 중단해라"는 터미널 명령입니다. 서버가 종료되면 브라우저에서 localhost:3000에 접속해도 페이지가 뜨지 않습니다.
주의할 점이 하나 있습니다. Ctrl + Z는 Ctrl + C와 다릅니다. Ctrl + Z는 프로그램을 "일시 중지"하는 것이지 종료하는 것이 아닙니다. 서버가 포트를 잡고 있는 상태가 유지됩니다. 이 상태에서 node server.js를 다시 실행하면 에러가 납니다. 반드시 Ctrl + C로 종료하세요.
실수로 Ctrl + Z를 눌렀다면 당황하지 않아도 됩니다. 터미널에 fg를 입력하고 엔터를 치면 일시 중지된 프로그램이 다시 전면으로 돌아옵니다. 그 상태에서 Ctrl + C를 눌러 정상적으로 종료하면 됩니다. 만약 fg가 동작하지 않는다면, 아래의 EADDRINUSE 에러 해결 방법으로 포트를 점유한 프로세스를 직접 종료할 수 있습니다.
EADDRINUSE 에러
서버를 제대로 종료하지 않았거나, 같은 포트를 쓰는 다른 프로그램이 이미 실행 중일 때 다음 에러가 나옵니다.
Error: listen EADDRINUSE: address already in use :::3000
"3000번 포트를 이미 누군가 사용하고 있다"는 뜻입니다. 이 에러는 Node.js를 시작할 때 거의 반드시 한 번은 만나게 됩니다. 해결 방법은 해당 포트를 사용 중인 프로세스를 찾아서 종료하는 것입니다.
맥/리눅스에서 해결하기:
# 3000번 포트를 사용 중인 프로세스 확인 lsof -i :3000 # 출력 예시: # COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME # node 12345 user 22u IPv6 0x... 0t0 TCP *:3000 (LISTEN) # PID(프로세스 ID) 숫자를 확인한 후 종료 kill 12345 # 그래도 안 끝나면 강제 종료 kill -9 12345
lsof -i :3000은 "3000번 포트를 사용하는 프로세스를 보여달라"는 명령입니다. 출력 결과에서 PID 열의 숫자를 확인한 후 kill 명령으로 해당 프로세스를 종료합니다.
윈도우에서 해결하기:
# 3000번 포트를 사용 중인 프로세스 확인 netstat -ano | findstr :3000 # 출력 예시: # TCP 0.0.0.0:3000 0.0.0.0:0 LISTENING 12345 # 맨 오른쪽 숫자(PID)를 확인한 후 종료 taskkill /PID 12345 /F
이 방법이 번거롭다면, 간단하게 포트 번호를 바꿔서 실행하는 방법도 있습니다. server.js에서 3000을 3001이나 8080으로 바꾸면 됩니다.
require와 import, 뭐가 다른 건가
코드를 직접 실행해보면서 require()를 사용했는데, 온라인 자료를 찾아보면 같은 Express 서버 코드인데 이렇게 쓰인 곳도 있습니다.
import express from 'express';
처음 배우는 입장에서 "어떤 게 맞는 건지" 혼란스러울 수 있습니다.
결론부터 말하면, 둘 다 맞습니다. require()는 CommonJS(CJS)라는 Node.js 초기부터 사용된 방식이고, import는 ECMAScript Modules(ESM)라는 JavaScript 공식 표준 방식입니다. 하는 일은 같습니다. 외부 코드를 현재 파일로 가져오는 거죠.
import가 JavaScript 표준이긴 하지만, Node.js에서 사용하려면 package.json에 "type": "module" 설정을 추가해야 하는 등 초기 설정이 필요합니다. 거기다 오래된 튜토리얼, 기존 프로젝트 코드, npm 패키지의 예제 대부분이 require()로 되어 있고요. 입문 단계에서는 설정 없이 바로 동작하는 require()로 시작하는 것이 현실적입니다.
이 시리즈에서는 require()를 사용합니다. 나중에 import를 사용하는 프로젝트를 접하게 되더라도 "아, 같은 역할인데 문법만 다른 거구나"라고 이해하면 됩니다.
직접 해보기
여기까지 따라왔다면 두 가지를 시도해보세요.
1. 포트 번호 바꿔보기
server.js에서 3000을 8080으로 바꿔봅니다.
app.listen(8080, function() { console.log('서버가 http://localhost:8080 에서 실행 중입니다'); });
서버를 Ctrl + C로 종료하고 node server.js로 다시 실행합니다. 브라우저에서 http://localhost:8080으로 접속하면 같은 내용이 보입니다. 포트 번호만 바뀌었을 뿐, 동작은 같습니다. 서버 코드를 수정하면 반드시 서버를 껐다 켜야 한다는 것을 기억하세요.
2. 경로 추가해보기
app.get('/', ...) 아래에 새 경로를 추가해봅니다.
app.get('/hello', function(req, res) { res.send('반갑습니다! /hello 경로에 접속했습니다.'); });
서버를 재시작하고 http://localhost:3000/hello로 접속하면 새 메시지가 보입니다. / 주소와 /hello 주소에 각각 다른 응답을 등록한 것입니다. 이런 식으로 주소별로 다른 동작을 하게 만드는 것을 라우팅(Routing)이라고 합니다.
정리
이번 편에서 한 것을 정리합니다.
Node.js를 설치했습니다. LTS 버전을 선택했고, node --version으로 설치를 확인했죠. 터미널에서 node hello.js로 JavaScript 파일을 실행해봤고, 브라우저 없이 JavaScript가 동작하는 것을 눈으로 확인했습니다. npm init -y로 프로젝트를 만들고, npm install express로 Express를 설치한 다음, 8줄짜리 코드로 웹 서버를 띄워서 브라우저에서 "안녕하세요!" 메시지를 확인했습니다.
이 과정에서 만난 문법들을 분류하면 다음과 같습니다.
JavaScript 표준 문법 (브라우저에서도 Node.js에서도 동작): const, let, function, 화살표 함수 () => {}, console.log()
Node.js 전용 문법 (브라우저에서는 동작하지 않음): require()
Express가 제공하는 기능 (npm install express 후 사용 가능): express(), app.get(), app.listen(), res.send()
다음 편에서는 이 서버가 텍스트 대신 HTML 파일을 보내도록 바꿉니다. 메모장 앱의 화면(HTML, CSS)을 만들고 Express로 서빙하는 것이 Part 2의 목표입니다.
참고 자료
- Node.js 공식 사이트: https://nodejs.org/en/about
- Node.js 브라우저와의 차이점: https://nodejs.org/en/learn/getting-started/differences-between-nodejs-and-the-browser
- Express 공식 문서 - 설치: https://expressjs.com/en/starter/installing.html
- Express 공식 문서 - Hello World: https://expressjs.com/en/starter/hello-world.html
- npm 공식 문서 - package.json: https://docs.npmjs.com/files/package.json/
- nvm 공식 GitHub: https://github.com/nvm-sh/nvm
- EADDRINUSE 에러 해결: https://betterstack.com/community/questions/how-to-fix-eaddrinuse-node-js/
- CommonJS vs ES Modules: https://betterstack.com/community/guides/scaling-nodejs/commonjs-vs-esm/
- Node.js 사용 통계: https://electroiq.com/stats/node-js-statistics/






댓글
댓글을 작성하려면 이 필요합니다.