[2026] Node.js 시작하기 | 설치, 설정, Hello World

[2026] Node.js 시작하기 | 설치, 설정, Hello World

이 글의 핵심

Node.js 시작하기: 설치, 설정, Hello World. Node.js vs 브라우저 JavaScript·Node.js 설치.

들어가며

Node.js란?

Node.js는 Chrome V8 JavaScript 엔진으로 빌드된 JavaScript 런타임 환경입니다. 브라우저 밖에서 JavaScript를 실행할 수 있게 해줍니다. 이벤트 루프를 한 가지로 비유하면, 식당에서 주문을 받는 직원 한 명이 테이블마다 “음식 나오면 알려 드릴게요”라고 번호를 남기고 다음 손님을 받는 것과 비슷합니다. 파일·네트워크처럼 시간이 걸리는 일은 주방(운영체제·스레드 풀)에 맡겨 두고, 끝나면 등록해 둔 콜백을 순서에 맞춰 처리합니다. 우체국에서 소포를 부치고 번호표를 받아 나중에 찾으러 오는 흐름으로 이해하셔도 됩니다. 주요 특징:

  • 비동기 I/O(한 작업이 끝나기를 기다리지 않고 다음 일을 넘기는 입출력): Non-blocking I/O로 높은 성능
  • 단일 스레드: 이벤트 루프 기반
  • 크로스 플랫폼: Windows, macOS, Linux 지원
  • npm: 세계 최대 패키지 저장소
  • JavaScript: 프론트엔드와 같은 언어 사용 Node.js가 적합한 경우:
  • ✅ REST API 서버
  • ✅ 실시간 애플리케이션 (채팅, 게임)
  • ✅ 마이크로서비스
  • ✅ CLI 도구
  • ✅ 스트리밍 서비스 Node.js가 부적합한 경우:
  • ❌ CPU 집약적 작업 (이미지/비디오 처리)
  • ❌ 복잡한 계산 작업

실무에서 마주한 현실

개발을 배울 때는 모든 게 깔끔하고 이론적입니다. 하지만 실무는 다릅니다. 레거시 코드와 씨름하고, 급한 일정에 쫓기고, 예상치 못한 버그와 마주합니다. 이 글에서 다루는 내용도 처음엔 이론으로 배웠지만, 실제 프로젝트에 적용하면서 “아, 이래서 이렇게 설계하는구나” 하고 깨달은 것들입니다. 특히 기억에 남는 건 첫 프로젝트에서 겪은 시행착오입니다. 책에서 배운 대로 했는데 왜 안 되는지 몰라 며칠을 헤맸죠. 결국 선배 개발자의 코드 리뷰를 통해 문제를 발견했고, 그 과정에서 많은 걸 배웠습니다. 이 글에서는 이론뿐 아니라 실전에서 마주칠 수 있는 함정들과 해결 방법을 함께 다루겠습니다.

1. Node.js vs 브라우저 JavaScript

비교

특징브라우저 JavaScriptNode.js
실행 환경브라우저 (Chrome, Firefox)서버, 로컬 머신
전역 객체windowglobal
DOM 접근
파일 시스템✅ (fs 모듈)
HTTP 서버✅ (http 모듈)
모듈 시스템ES ModulesCommonJS + ES Modules
패키지 관리없음npm, yarn

공통 기능

브라우저와 Node.js 모두에서 사용할 수 있는 JavaScript 표준 기능들입니다: 다음은 javascript를 활용한 상세한 구현 코드입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// 콘솔 출력 - 디버깅과 로깅에 사용
console.log("Hello");
// 타이머 함수 - 일정 시간 후 코드 실행
setTimeout(() => {
    console.log("1초 후 실행");
}, 1000);
// 반복 타이머 - 일정 간격으로 코드 반복 실행
setInterval(() => {
    console.log("1초마다 실행");
}, 1000);
// 비동기 처리 - Promise와 async/await 문법
const fetchData = async () => {
    const result = await Promise.resolve("데이터");
    return result;
};
// JSON 파싱 - 문자열을 객체로, 객체를 문자열로 변환
const obj = JSON.parse('{"name": "홍길동"}');
const str = JSON.stringify({ name: "홍길동" });

브라우저와 Node.js 모두 같은 ECMAScript 문법으로 Promiseasync/await를 씁니다. JSON.parseJSON.stringify는 API 응답·.env를 다룰 때 문자열과 객체를 오갈 때마다 사용합니다.

Node.js 전용 기능

Node.js에서만 사용할 수 있는 서버 사이드 기능들입니다: 다음은 javascript를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// 파일 시스템 - 파일 읽기/쓰기 기능
const fs = require('fs');
// readFileSync: 파일을 동기적으로 읽음 (파일을 다 읽을 때까지 대기)
// 'utf8': 텍스트 인코딩 지정 (한글 등 문자 처리)
const content = fs.readFileSync('file.txt', 'utf8');
// HTTP 서버 - 웹 서버 생성 기능
const http = require('http');
// createServer: 서버 인스턴스 생성
// req: 클라이언트 요청 객체, res: 서버 응답 객체
const server = http.createServer((req, res) => {
    res.end('Hello'); // 응답 전송 후 연결 종료
});
// 경로 처리 - 파일 경로를 안전하게 조작
const path = require('path');
// __dirname: 현재 스크립트가 있는 디렉토리의 절대 경로
// join: 경로를 OS에 맞게 결합 (Windows: \, Linux: /)
const filePath = path.join(__dirname, 'file.txt');
// 프로세스 정보 - 현재 실행 중인 Node.js 프로세스 정보
console.log(process.version);   // Node.js 버전 (예: v20.11.0)
console.log(process.platform);  // 운영체제 (예: win32, darwin, linux)
console.log(process.cwd());     // 현재 작업 디렉토리
console.log(process.pid);       // 프로세스 ID

fs는 비동기(readFile)와 동기(readFileSync)를 둘 다 제공합니다. 요청을 처리하는 콜백 안에서 readFileSync를 쓰면 그동안 다른 HTTP 요청도 기다리게 되므로, 서버 코드에서는 비동기 API가 기본입니다. path.join은 Windows의 \와 POSIX의 /를 섞지 않도록 경로를 이어 줍니다.

2. Node.js 설치

Windows

  1. nodejs.org 방문
  2. LTS 버전 다운로드 (안정 버전, 권장)
  3. 설치 프로그램 실행
  4. 설치 확인: 아래 코드는 bash를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
node --version
# v20.11.0
npm --version
# 10.2.4

macOS

방법 1: 공식 설치 프로그램

# nodejs.org에서 다운로드

방법 2: Homebrew 아래 코드는 bash를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

brew install node
# 버전 확인
node --version
npm --version

Linux (Ubuntu/Debian)

아래 코드는 bash를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# NodeSource 저장소 추가
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
# 설치
sudo apt-get install -y nodejs
# 버전 확인
node --version
npm --version

버전 관리 (nvm)

여러 Node.js 버전을 관리하려면 nvm 사용: 다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# nvm 설치 (Linux/macOS)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
# Node.js 설치
nvm install 20
nvm install 18
# 버전 전환
nvm use 20
nvm use 18
# 현재 버전
nvm current
# 설치된 버전 목록
nvm list

3. 첫 Node.js 프로그램

Hello World

아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// hello.js
console.log("Hello, Node.js!");
// 현재 Node.js 버전
console.log(`Node.js 버전: ${process.version}`);
// 플랫폼 정보
console.log(`플랫폼: ${process.platform}`);

실행: 다음은 간단한 bash 코드 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

node hello.js
# Hello, Node.js!
# Node.js 버전: v20.11.0
# 플랫폼: win32

명령줄 인자

다음은 javascript를 활용한 상세한 구현 코드입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// args.js
console.log("명령줄 인자:", process.argv);
// process.argv[0]: node 실행 파일 경로
// process.argv[1]: 스크립트 파일 경로
// process.argv[2~]: 사용자 인자
const args = process.argv.slice(2);
console.log("사용자 인자:", args);
if (args.length === 0) {
    console.log("사용법: node args.js <이름>");
    process.exit(1);
}
const name = args[0];
console.log(`안녕하세요, ${name}님!`);

실행:

node args.js 홍길동
# 안녕하세요, 홍길동님!

환경 변수

아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// env.js
console.log("환경 변수:", process.env);
// 특정 환경 변수
const port = process.env.PORT || 3000;
const nodeEnv = process.env.NODE_ENV || 'development';
console.log(`포트: ${port}`);
console.log(`환경: ${nodeEnv}`);

실행: 아래 코드는 bash를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# Windows
set PORT=8080 && node env.js
# Linux/macOS
PORT=8080 node env.js

4. 첫 HTTP 서버

기본 서버

가장 간단한 형태의 HTTP 서버를 작성해 봅니다. 다음은 javascript를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// server.js
const http = require('http');
// createServer: 서버 인스턴스 생성
// 콜백 함수는 요청이 올 때마다 실행됨
const server = http.createServer((req, res) => {
    // req.method: HTTP 메서드 (GET, POST 등)
    // req.url: 요청된 URL 경로 (예: /, /about)
    console.log(`${req.method} ${req.url}`);
    
    // writeHead: HTTP 상태 코드와 헤더 설정
    // 200: 성공 응답
    // Content-Type: 응답 데이터 형식 지정
    // charset=utf-8: 한글 등 유니코드 문자 처리
    res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
    
    // end: 응답 본문을 전송하고 연결 종료
    res.end('안녕하세요, Node.js 서버입니다!');
});
// 서버를 특정 포트에서 실행
const PORT = 3000;
server.listen(PORT, () => {
    // 서버가 시작되면 이 콜백이 실행됨
    console.log(`서버가 http://localhost:${PORT} 에서 실행 중`);
});

코드 흐름:

  1. http 모듈을 불러옵니다.
  2. createServer요청이 올 때마다 호출될 함수를 넘깁니다(콜백).
  3. listen으로 포트 3000에서 연결을 받을 준비를 합니다.
  4. 브라우저 등이 접속하면 req·res가 채워진 채로 위 콜백이 실행됩니다.
  5. writeHead·end로 상태 코드·본문을 보내고 응답을 마칩니다. 실행:
node server.js
# 서버가 http://localhost:3000 에서 실행 중

브라우저에서 http://localhost:3000 접속하면 메시지가 표시됩니다.

라우팅 추가

URL 경로에 따라 다른 응답을 반환하는 라우팅 기능을 구현합니다: 다음은 javascript를 활용한 상세한 구현 코드입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// server-routing.js
const http = require('http');
const server = http.createServer((req, res) => {
    // 구조 분해로 요청 메서드와 URL 추출
    const { method, url } = req;
    
    // 모든 응답에 공통으로 적용할 헤더 설정
    res.setHeader('Content-Type', 'text/plain; charset=utf-8');
    
    // URL과 메서드에 따라 분기 처리
    if (url === '/' && method === 'GET') {
        // 루트 경로 - 홈 페이지
        res.writeHead(200);  // 200: OK 상태 코드
        res.end('홈 페이지');
    } else if (url === '/about' && method === 'GET') {
        // /about 경로 - 소개 페이지
        res.writeHead(200);
        res.end('소개 페이지');
    } else if (url === '/api/users' && method === 'GET') {
        // API 엔드포인트 - JSON 응답
        res.writeHead(200, { 'Content-Type': 'application/json' });
        // JavaScript 객체를 JSON 문자열로 변환하여 응답
        res.end(JSON.stringify({ users: ['홍길동', '김철수'] }));
    } else {
        // 매칭되는 경로가 없으면 404 에러
        res.writeHead(404);  // 404: Not Found 상태 코드
        res.end('페이지를 찾을 수 없습니다');
    }
});
server.listen(3000, () => {
    console.log('서버 실행 중: http://localhost:3000');
});

라우팅 동작 원리:

  1. 클라이언트가 특정 URL로 요청
  2. req.urlreq.method를 확인
  3. 조건문으로 매칭되는 경로 찾기
  4. 해당 경로에 맞는 응답 반환
  5. 매칭되는 경로가 없으면 404 에러 테스트: 다음은 간단한 bash 코드 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
# 브라우저 또는 curl로 테스트
curl http://localhost:3000/
curl http://localhost:3000/about
curl http://localhost:3000/api/users

HTML 응답

다음은 javascript를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// server-html.js
const http = require('http');
const server = http.createServer((req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
    
    const html = `
        <!DOCTYPE html>
        <html>
        <head>
            <title>Node.js 서버</title>
            <style>
                body {
                    font-family: Arial, sans-serif;
                    max-width: 800px;
                    margin: 50px auto;
                    padding: 20px;
                }
                h1 { color: #68a063; }
            </style>
        </head>
        <body>
            <h1>Node.js 서버에 오신 것을 환영합니다!</h1>
            <p>현재 시간: ${new Date().toLocaleString('ko-KR')}</p>
            <p>요청 URL: ${req.url}</p>
            <p>요청 메서드: ${req.method}</p>
        </body>
        </html>
    `;
    
    res.end(html);
});
server.listen(3000, () => {
    console.log('서버 실행 중: http://localhost:3000');
});

5. npm (Node Package Manager)

package.json 생성

아래 코드는 bash를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# 프로젝트 폴더 생성
mkdir my-node-project
cd my-node-project
# package.json 생성 (대화형)
npm init
# package.json 생성 (기본값 사용)
npm init -y

생성된 package.json: 아래 코드는 json를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

{
  "name": "my-node-project",
  "version": "1.0.0",
  "description": "Node.js 프로젝트",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

패키지 설치

아래 코드는 bash를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 프로젝트 의존성 설치
npm install express
# 여러 패키지 동시 설치
npm install express body-parser cors
# 개발 의존성 설치 (배포 시 제외)
npm install --save-dev nodemon eslint
# 전역 설치
npm install -g nodemon
# 특정 버전 설치
npm install express@4.18.0

package.json 업데이트: 아래 코드는 json를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

{
  "dependencies": {
    "express": "^4.18.2"
  },
  "devDependencies": {
    "nodemon": "^3.0.1"
  }
}

패키지 관리

다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 설치된 패키지 목록
npm list
# 패키지 업데이트
npm update
# 패키지 제거
npm uninstall express
# 보안 취약점 검사
npm audit
# 취약점 자동 수정
npm audit fix
# 캐시 정리
npm cache clean --force

package.json scripts

아래 코드는 json를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

{
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "test": "jest",
    "lint": "eslint .",
    "build": "webpack"
  }
}

실행:

npm start      # node index.js
npm run dev    # nodemon index.js
npm test       # jest

6. 모듈 시스템

CommonJS (기본)

Node.js의 기본 모듈 시스템입니다. 코드를 재사용 가능한 모듈로 분리할 수 있습니다. 내보내기 (module.exports): 다음은 javascript를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// math.js - 수학 관련 함수들을 모듈로 만들기
function add(a, b) {
    return a + b;
}
function subtract(a, b) {
    return a - b;
}
const PI = 3.14159;
// 방법 1: 객체로 내보내기 (권장)
// module.exports에 객체를 할당하면 해당 객체가 모듈의 공개 API가 됨
module.exports = {
    add,        // add: add와 동일 (ES6 단축 속성)
    subtract,
    PI
};
// 방법 2: 개별 내보내기
// exports 객체에 속성을 추가하는 방식
// 주의: exports = {}는 작동하지 않음 (참조가 끊김)
exports.add = add;
exports.subtract = subtract;
exports.PI = PI;

가져오기 (require): 아래 코드는 javascript를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// app.js - math 모듈 사용하기
// require: 모듈을 불러와서 module.exports 객체를 반환
// './math': 상대 경로 (./ = 현재 디렉토리)
const math = require('./math');
// 모듈의 함수와 변수 사용
console.log(math.add(10, 5));       // 15
console.log(math.subtract(10, 5));  // 5
console.log(math.PI);               // 3.14159
// 구조 분해 할당 - 필요한 것만 추출
// 코드가 더 간결해지고 가독성이 향상됨
const { add, subtract } = require('./math');
console.log(add(10, 5));  // 15 - math. 접두사 없이 바로 사용

모듈 캐싱:

  • require는 모듈을 처음 불러올 때만 실행하고, 이후에는 캐시된 결과를 반환
  • 같은 모듈을 여러 번 require해도 한 번만 실행됨
  • 모듈은 싱글톤 패턴처럼 동작

ES Modules (최신)

package.json 설정:

{
  "type": "module"
}

내보내기 (export): 다음은 javascript를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// math.mjs (또는 .js with "type": "module")
export function add(a, b) {
    return a + b;
}
export function subtract(a, b) {
    return a - b;
}
export const PI = 3.14159;
// 기본 내보내기
export default function multiply(a, b) {
    return a * b;
}

가져오기 (import): 아래 코드는 javascript를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// app.mjs
// 필요한 모듈 import
import multiply, { add, subtract, PI } from './math.mjs';
console.log(add(10, 5));       // 15
console.log(multiply(10, 5));  // 50
console.log(PI);               // 3.14159
// 모두 가져오기
import * as math from './math.mjs';
console.log(math.add(10, 5));

내장 모듈

다음은 javascript를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// 파일 시스템
const fs = require('fs');
// 경로 처리
const path = require('path');
// HTTP
const http = require('http');
// URL 처리
const url = require('url');
// 운영체제 정보
const os = require('os');
// 이벤트
const EventEmitter = require('events');

7. 파일 시스템 (fs)

동기 vs 비동기

Node.js의 핵심인 동기·비동기 처리 방식을 짚어 봅니다. 동기 (Sync): 작업이 끝날 때까지 대기 아래 코드는 javascript를 사용한 구현 예제입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

const fs = require('fs');
try {
    // readFileSync: 파일을 다 읽을 때까지 다음 코드 실행 안 됨 (블로킹)
    // 파일이 크면 프로그램이 멈춘 것처럼 보임
    const data = fs.readFileSync('file.txt', 'utf8');
    console.log(data);  // 파일 내용 출력
} catch (err) {
    // 파일이 없거나 권한이 없으면 에러 발생
    console.error('에러:', err.message);
}
// 파일 읽기가 완전히 끝난 후에 실행됨
console.log('파일 읽기 완료');

동기 방식의 문제점:

  • 파일 읽기가 끝날 때까지 다른 작업을 할 수 없음
  • 서버에서 사용하면 다른 요청을 처리할 수 없어 성능 저하
  • 초기화 코드나 간단한 스크립트에만 사용 권장 비동기 (Callback): 작업을 백그라운드에서 실행 다음은 javascript를 활용한 상세한 구현 코드입니다. 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
const fs = require('fs');
// readFile: 파일 읽기를 백그라운드에서 실행 (논블로킹)
// 파일 읽기가 완료되면 콜백 함수가 호출됨
fs.readFile('file.txt', 'utf8', (err, data) => {
    // 콜백 함수: 작업 완료 후 실행되는 함수
    // Node.js 관례: 첫 번째 인자는 항상 에러 객체
    if (err) {
        console.error('에러:', err.message);
        return;  // 에러가 있으면 여기서 종료
    }
    // 에러가 없으면 data에 파일 내용이 담김
    console.log(data);
});
// 파일 읽기와 동시에 바로 실행됨 (대기하지 않음)
console.log('파일 읽기 시작됨');
// 출력 순서: "파일 읽기 시작됨" → 파일 내용

비동기 방식의 장점:

  • 파일 읽기 중에도 다른 작업 가능
  • 서버가 여러 요청을 동시에 처리 가능
  • Node.js의 핵심 강점 비동기 (Promise): 최신 방식 다음은 javascript를 활용한 상세한 구현 코드입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// fs.promises: Promise 기반 파일 시스템 API
const fs = require('fs').promises;
async function readFileAsync() {
    try {
        // await: Promise가 완료될 때까지 대기 (하지만 다른 작업은 블로킹하지 않음)
        // 코드는 동기처럼 보이지만 실제로는 비동기로 동작
        const data = await fs.readFile('file.txt', 'utf8');
        console.log(data);
    } catch (err) {
        // try-catch로 에러 처리 (콜백보다 직관적)
        console.error('에러:', err.message);
    }
}
// async 함수는 항상 Promise를 반환
readFileAsync();

Promise 방식의 장점:

  • 콜백 지옥(callback hell) 방지
  • 에러 처리가 더 직관적 (try-catch)
  • 코드 가독성 향상
  • 현대적인 JavaScript 스타일

파일 읽기/쓰기

다음은 javascript를 활용한 상세한 구현 코드입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

const fs = require('fs').promises;
async function fileOperations() {
    try {
        // 파일 쓰기
        await fs.writeFile('output.txt', 'Hello, Node.js!', 'utf8');
        console.log('파일 쓰기 완료');
        
        // 파일 읽기
        const data = await fs.readFile('output.txt', 'utf8');
        console.log('파일 내용:', data);
        
        // 파일 추가
        await fs.appendFile('output.txt', '\n추가 내용', 'utf8');
        
        // 파일 존재 확인
        const exists = await fs.access('output.txt')
            .then(() => true)
            .catch(() => false);
        console.log('파일 존재:', exists);
        
        // 파일 삭제
        await fs.unlink('output.txt');
        console.log('파일 삭제 완료');
        
    } catch (err) {
        console.error('에러:', err.message);
    }
}
fileOperations();

8. 실전 예제

예제 1: 간단한 웹 서버

다음은 javascript를 활용한 상세한 구현 코드입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// simple-server.js
const http = require('http');
const fs = require('fs').promises;
const path = require('path');
const server = http.createServer(async (req, res) => {
    console.log(`${req.method} ${req.url}`);
    
    if (req.url === '/') {
        res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
        res.end(`
            <html>
                <head><title>Node.js 서버</title></head>
                <body>
                    <h1>환영합니다!</h1>
                    <ul>
                        <li><a href="/about">소개</a></li>
                        <li><a href="/api/time">현재 시간 API</a></li>
                    </ul>
                </body>
            </html>
        `);
    } else if (req.url === '/about') {
        res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
        res.end('<h1>소개 페이지</h1><p>Node.js로 만든 서버입니다.</p>');
    } else if (req.url === '/api/time') {
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({
            time: new Date().toISOString(),
            timestamp: Date.now()
        }));
    } else {
        res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
        res.end('404 - 페이지를 찾을 수 없습니다');
    }
});
const PORT = 3000;
server.listen(PORT, () => {
    console.log(`서버 실행 중: http://localhost:${PORT}`);
    console.log('종료하려면 Ctrl+C를 누르세요');
});

예제 2: 파일 서버

다음은 javascript를 활용한 상세한 구현 코드입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// file-server.js
const http = require('http');
const fs = require('fs').promises;
const path = require('path');
const MIME_TYPES = {
    '.html': 'text/html',
    '.css': 'text/css',
    '.js': 'application/javascript',
    '.json': 'application/json',
    '.png': 'image/png',
    '.jpg': 'image/jpeg',
    '.txt': 'text/plain'
};
const server = http.createServer(async (req, res) => {
    try {
        let filePath = '.' + req.url;
        if (filePath === './') {
            filePath = './index.html';
        }
        
        const ext = path.extname(filePath);
        const contentType = MIME_TYPES[ext] || 'application/octet-stream';
        
        const data = await fs.readFile(filePath);
        
        res.writeHead(200, { 'Content-Type': contentType });
        res.end(data);
        
        console.log(`✓ ${req.url}`);
    } catch (err) {
        if (err.code === 'ENOENT') {
            res.writeHead(404, { 'Content-Type': 'text/plain' });
            res.end('404 - File Not Found');
        } else {
            res.writeHead(500);
            res.end('500 - Internal Server Error');
        }
        console.error(`✗ ${req.url}: ${err.message}`);
    }
});
server.listen(3000, () => {
    console.log('파일 서버 실행 중: http://localhost:3000');
});

예제 3: CLI 도구

다음은 javascript를 활용한 상세한 구현 코드입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// cli-tool.js
const fs = require('fs').promises;
const path = require('path');
async function countFiles(directory) {
    try {
        const files = await fs.readdir(directory);
        
        let fileCount = 0;
        let dirCount = 0;
        
        for (const file of files) {
            const filePath = path.join(directory, file);
            const stats = await fs.stat(filePath);
            
            if (stats.isDirectory()) {
                dirCount++;
            } else {
                fileCount++;
            }
        }
        
        console.log(`\n디렉토리: ${directory}`);
        console.log(`파일: ${fileCount}개`);
        console.log(`폴더: ${dirCount}개`);
        console.log(`총: ${fileCount + dirCount}개`);
        
    } catch (err) {
        console.error('에러:', err.message);
        process.exit(1);
    }
}
// 명령줄 인자로 디렉토리 받기
const directory = process.argv[2] || '.';
countFiles(directory);

실행:

node cli-tool.js
node cli-tool.js ./src

9. nodemon (자동 재시작)

설치

아래 코드는 bash를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# 전역 설치
npm install -g nodemon
# 프로젝트 개발 의존성으로 설치
npm install --save-dev nodemon

사용

# node 대신 nodemon 사용
nodemon server.js
# 파일 변경 시 자동으로 재시작됨

package.json 설정

아래 코드는 json를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

{
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js"
  }
}
npm run dev

nodemon.json 설정

아래 코드는 json를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

{
  "watch": [src],
  "ext": "js,json",
  "ignore": ["node_modules", "test"],
  "delay": 1000
}

10. 디버깅

console.log 디버깅

아래 코드는 javascript를 사용한 구현 예제입니다. 에러 처리를 통해 안정성을 확보합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

console.log('변수:', variable);
console.log('객체:', JSON.stringify(obj, null, 2));
console.error('에러:', error);
console.warn('경고:', warning);
console.table([{ name: '홍길동', age: 25 }]);

VS Code 디버거

.vscode/launch.json: 아래 코드는 json를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch Program",
      "skipFiles": [<node_internals>/**],
      "program": "${workspaceFolder}/index.js"
    }
  ]
}

사용법:

  1. 중단점(breakpoint) 설정
  2. F5 또는 디버그 시작
  3. 변수 값 확인, 단계별 실행

Node.js 내장 디버거

아래 코드는 bash를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

node inspect server.js
# 디버거 명령어
# cont (c): 계속 실행
# next (n): 다음 줄
# step (s): 함수 안으로
# out (o): 함수 밖으로
# repl: REPL 모드

11. 환경 변수 관리

.env 파일

# .env 파일 설치
npm install dotenv

.env: 다음은 간단한 code 코드 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

PORT=3000
NODE_ENV=development
DATABASE_URL=mongodb://localhost:27017/mydb
API_KEY=your-secret-key

사용: 아래 코드는 javascript를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// config.js
require('dotenv').config();
const config = {
    port: process.env.PORT || 3000,
    nodeEnv: process.env.NODE_ENV || 'development',
    databaseUrl: process.env.DATABASE_URL,
    apiKey: process.env.API_KEY
};
module.exports = config;

아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// server.js
const config = require('./config');
console.log(`포트: ${config.port}`);
console.log(`환경: ${config.nodeEnv}`);

.gitignore:

node_modules/
.env

12. 자주 발생하는 문제

문제 1: 포트 이미 사용 중

에러:

Error: listen EADDRINUSE: address already in use :::3000

해결: 아래 코드는 bash를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# Windows
netstat -ano | findstr :3000
taskkill /PID <PID> /F
# Linux/macOS
lsof -i :3000
kill -9 <PID>
# 또는 다른 포트 사용
const PORT = process.env.PORT || 3001;

문제 2: 모듈을 찾을 수 없음

에러:

Error: Cannot find module 'express'

해결: 아래 코드는 bash를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# node_modules 확인
ls node_modules
# 패키지 재설치
npm install
# 특정 패키지 설치
npm install express

문제 3: 경로 문제

아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// ❌ 잘못된 경로
const data = fs.readFileSync('file.txt');
// ✅ 절대 경로 사용
const path = require('path');
const filePath = path.join(__dirname, 'file.txt');
const data = fs.readFileSync(filePath, 'utf8');

문제 4: 비동기 처리 실수

아래 코드는 javascript를 사용한 구현 예제입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ 비동기 결과를 기다리지 않음
fs.readFile('file.txt', 'utf8', (err, data) => {
    console.log(data);
});
console.log('완료');  // 먼저 출력됨!
// ✅ async/await 사용
async function readFile() {
    const data = await fs.promises.readFile('file.txt', 'utf8');
    console.log(data);
    console.log('완료');
}

13. 실전 팁

프로젝트 구조

아래 코드는 code를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

my-node-project/
├── src/
│   ├── controllers/
│   ├── models/
│   ├── routes/
│   └── utils/
├── public/
├── tests/
├── .env
├── .gitignore
├── package.json
├── README.md
└── server.js

베스트 프랙티스

다음은 javascript를 활용한 상세한 구현 코드입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ✅ 에러 처리
process.on('uncaughtException', (err) => {
    console.error('예상치 못한 에러:', err);
    process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
    console.error('처리되지 않은 Promise 거부:', reason);
});
// ✅ Graceful Shutdown
process.on('SIGTERM', () => {
    console.log('SIGTERM 신호 받음. 서버 종료 중...');
    server.close(() => {
        console.log('서버 종료됨');
        process.exit(0);
    });
});
// ✅ 환경 변수 사용
const PORT = process.env.PORT || 3000;
const NODE_ENV = process.env.NODE_ENV || 'development';
// ✅ 로깅
const isDev = NODE_ENV === 'development';
if (isDev) {
    console.log('개발 모드');
}

성능 최적화

다음은 javascript를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ✅ 스트림 사용 (대용량 파일)
// 변수 선언 및 초기화
const fs = require('fs');
const readStream = fs.createReadStream('large-file.txt');
const writeStream = fs.createWriteStream('output.txt');
readStream.pipe(writeStream);
// ✅ 클러스터링 (멀티 코어 활용)
const cluster = require('cluster');
const os = require('os');
if (cluster.isMaster) {
    const numCPUs = os.cpus().length;
    
    for (let i = 0; i < numCPUs; i++) {
        cluster.fork();
    }
} else {
    // 워커 프로세스에서 서버 실행
    http.createServer((req, res) => {
        res.end('Hello');
    }).listen(3000);
}

정리

핵심 요약

  1. Node.js: Chrome V8 기반 JavaScript 런타임
  2. 설치: nodejs.org에서 LTS 버전 다운로드
  3. 실행: node filename.js
  4. npm: 패키지 관리자, npm install <package>
  5. 모듈: CommonJS (require) 또는 ES Modules (import)
  6. 파일 시스템: fs 모듈, 동기/비동기
  7. HTTP 서버: http.createServer()
  8. 개발 도구: nodemon, VS Code 디버거

Node.js 장점

  • JavaScript 통일: 프론트엔드와 백엔드 모두 JavaScript
  • 비동기 I/O: 높은 동시 처리 성능
  • npm 생태계: 수백만 개의 패키지
  • 빠른 개발: 간결한 코드, 빠른 프로토타이핑
  • 활발한 커뮤니티: 풍부한 학습 자료

다음 단계

추천 학습 자료

공식 문서:


다른 언어와 비교


관련 글

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3