웹 개발을 시작하면서 백엔드 서버를 직접 만들어야 하는데, 막막하셨나요? JavaScript로 프론트엔드는 다룰 수 있는데, 서버 개발은 또 다른 언어를 배워야 하는 건 아닌지 고민되셨을 겁니다. Express.js는 바로 이런 분들을 위한 프레임워크입니다. 이미 알고 있는 JavaScript로 서버를 만들 수 있으니까요.
오늘은 Express.js가 무엇인지, 왜 많은 개발자들이 선택하는지, 그리고 어떻게 시작하면 되는지 차근차근 알아보겠습니다.
1. Express.js, 도대체 뭐길래 이렇게 유명할까?
Express.js는 Node.js 환경에서 돌아가는 웹 서버 프레임워크입니다. 웹 서버를 만들 때 필요한 기능들을 미리 만들어둔 도구 세트라고 생각하면 쉽습니다. Node.js만으로도 서버를 만들 수 있지만, 모든 걸 처음부터 구현하려면 정말 복잡하거든요.
2025년 3월 기준으로 Express 5.1.0이 최신 버전입니다. npm에서 주간 다운로드 수가 약 2,900만 회, GitHub 스타는 66,000개 이상입니다. Node.js 웹 프레임워크 중 압도적인 1위죠.
Express는 어떻게 탄생했을까?
2010년 5월, 캐나다 개발자 TJ Holowaychuk가 Ruby의 Sinatra에서 영감을 받아 만들었습니다. 놀라운 건 TJ가 Express뿐만 아니라 Mocha, Koa, Jade(지금의 Pug), Commander 등 100개가 넘는 오픈소스 프로젝트를 만든 전설적인 인물이라는 점입니다. 그의 코드 기여는 100만 줄이 넘어서, 일부 개발자들은 “TJ가 진짜 한 명이 맞나?”라고 의심할 정도였습니다.
2014년 TJ가 Node.js를 떠나면서 Express는 StrongLoop → IBM → Node.js Foundation으로 관리 주체가 바뀌었고, 개인 프로젝트에서 커뮤니티 프로젝트로 성장했습니다.
왜 Express가 이렇게 인기 있을까?
숫자가 말해줍니다. PayPal, Uber, IBM, Fox Sports, NASA 같은 대기업들이 Express를 사용합니다. 이유는 명확합니다:
- 검증된 안정성: 15년 가까이 사용되며 거의 모든 상황에서 검증됨
- 쉬운 학습: 초보자도 하루면 기본 서버를 만들 수 있음
- 방대한 생태계: 필요한 기능의 99%는 이미 누군가 만들어둠
- 활발한 커뮤니티: 문제가 생기면 구글 검색으로 답을 찾을 수 있음
- 취업 시장: Express 경험을 요구하는 구인 공고가 압도적으로 많음
Express는 딱 필요한 것만 제공하는 미니멀한 프레임워크입니다. “이렇게 해야 한다”고 강요하지 않아서(unopinionated), 개발자가 자유롭게 구조를 설계할 수 있습니다. 500줄 정도의 가벼운 코어에 필요한 기능은 미들웨어로 추가하는 방식이죠.
2. MEAN/MERN 스택의 핵심, Express의 역할
풀스택 개발을 공부해본 분들은 MEAN이나 MERN 스택을 들어보셨을 겁니다. 이 스택들의 공통점은? 바로 Express입니다.
MEAN 스택 = MongoDB + Express + Angular + Node.js
MERN 스택 = MongoDB + Express + React + Node.js
MEVN 스택 = MongoDB + Express + Vue + Node.js
이 스택들이 인기 있는 이유는 간단합니다. JavaScript 하나로 전체 애플리케이션을 개발할 수 있으니까요. 프론트엔드 개발자가 백엔드도 할 수 있어서 인력 운용이 효율적이고, 데이터 교환도 JSON으로 매끄럽게 이루어집니다.
Express는 이 스택에서 백엔드 프레임워크 역할을 합니다. 클라이언트 요청을 받아 처리하고, 데이터베이스와 통신하며, API를 제공하는 중간 계층이죠. 2025년 현재, 특히 MERN 스택은 스타트업과 빠른 프로토타이핑이 필요한 환경에서 가장 인기 있는 선택입니다.
3. Express vs 다른 프레임워크들 – 뭘 선택해야 할까?
Express가 1위이긴 하지만, 다른 선택지도 있습니다. 각각 언제 쓰는 게 좋을까요?
Fastify – 성능이 정말 중요하다면
“가장 빠른 프레임워크”를 목표로 만들어졌습니다. 벤치마크 결과 Express보다 2.5~4배 빠릅니다. 초당 72,000개 요청 vs Express 18,000개. 고성능 마이크로서비스나 실시간 API가 필요하면 Fastify가 좋습니다. 하지만 생태계가 Express만큼 크지 않고 학습 시간이 필요합니다.
Koa – Express 팀의 차세대 시도
Express를 만든 바로 그 팀이 만든 프레임워크입니다. async/await을 활용해 콜백 지옥에서 벗어나고, 에러 처리가 훨씬 간편합니다. 더 현대적이고 깔끔한 코드를 원한다면 Koa가 좋습니다. 다만 커뮤니티가 작고 미들웨어를 직접 만들어야 하는 경우가 많습니다.
Hapi – 엔터프라이즈급 대규모 서비스
Walmart가 블랙 프라이데이 트래픽을 감당하려고 만든 프레임워크입니다. 입력 검증, 캐싱, 인증이 내장되어 있고, 설정 중심 접근 방식을 사용합니다. 대기업 서비스에 적합하지만 학습 곡선이 가파릅니다.
NestJS – TypeScript와 체계적인 구조
Angular에서 영감받은 TypeScript 프레임워크입니다. 내부적으로 Express를 쓰지만 그 위에 구조화된 아키텍처를 제공합니다. 대규모 팀 프로젝트나 엔터프라이즈 개발에 좋습니다.
그래서 뭘 써야 할까?
- 처음 배우거나 중소규모 프로젝트: Express
- 극한의 성능이 필요한 API: Fastify
- 깔끔한 현대적 코드를 원함: Koa
- 대규모 엔터프라이즈: Hapi 또는 NestJS
하지만 대부분의 경우 Express가 정답입니다. 방대한 자료, 쉬운 학습, 검증된 안정성, 그리고 무엇보다 취업할 때 가장 많이 요구되는 기술이니까요.
4. 설치부터 첫 서버까지 – 실제로 만들어보기
Express를 사용하려면 먼저 Node.js가 설치되어 있어야 합니다. Express 5.x는 Node.js 18 이상이 필요합니다.
Node.js 설치 확인
터미널을 열고 이렇게 입력해보세요:
node --version
npm --version
버전이 나오면 이미 설치되어 있는 겁니다. 없다면 nodejs.org에서 LTS 버전을 다운로드하세요.
프로젝트 만들기
# 1. 프로젝트 폴더 생성
mkdir my-express-app
cd my-express-app
# 2. package.json 생성
npm init -y
# 3. Express 설치
npm install express
# 4. 개발 편의를 위해 nodemon 설치 (선택사항)
npm install --save-dev nodemon
nodemon이 뭔가요?
코드를 수정할 때마다 서버를 재시작하는 게 번거롭죠? nodemon은 파일이 변경되면 자동으로 서버를 재시작해줍니다. 개발할 때 정말 편합니다.
package.json에 scripts 추가
package.json
파일을 열어서 다음 부분을 추가하세요:
{
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
}
}
이제 npm run dev
로 개발 서버를, npm start
로 운영 서버를 실행할 수 있습니다.
첫 번째 서버 코드 작성
app.js
파일을 만들고 다음 코드를 작성하세요:
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(port, () => {
console.log(`서버가 http://localhost:${port} 에서 실행 중입니다`);
});
서버 실행
npm run dev
브라우저에서 http://localhost:3000
으로 접속하면 “Hello World!”가 보입니다. 축하합니다! 방금 첫 번째 Express 서버를 만들었습니다.
코드 한 줄씩 이해하기
const express = require('express')
: Express 모듈을 불러옵니다const app = express()
: Express 앱 인스턴스를 생성합니다app.get('/', ...)
: 루트 경로(/
)로 GET 요청이 오면 실행할 함수를 정의합니다req
: 요청(request) 정보가 담긴 객체res
: 응답(response)을 보낼 때 사용하는 객체app.listen(3000, ...)
: 3000번 포트에서 서버를 시작합니다
5. req와 res 객체 – 요청과 응답 다루기
Express에서 가장 많이 사용하는 두 객체를 제대로 알아야 합니다.
req (요청 객체) 주요 메서드
app.get('/user/:id', (req, res) => {
// URL 파라미터
const userId = req.params.id;
// 쿼리 파라미터 (?name=kim&age=25)
const name = req.query.name;
const age = req.query.age;
// POST로 받은 데이터 (express.json() 필요)
const data = req.body;
// 헤더 정보
const userAgent = req.get('User-Agent');
// 쿠키 (cookie-parser 필요)
const sessionId = req.cookies.sessionId;
// 요청 메서드와 경로
console.log(req.method); // GET, POST, PUT, DELETE 등
console.log(req.path); // /user/123
console.log(req.url); // /user/123?name=kim
});
res (응답 객체) 주요 메서드
app.get('/api/demo', (req, res) => {
// 1. 텍스트 응답
res.send('Hello World');
// 2. JSON 응답 (API에서 가장 많이 사용)
res.json({ name: '김철수', age: 25 });
// 3. 상태 코드와 함께 응답
res.status(404).json({ error: '찾을 수 없습니다' });
// 4. 리다이렉트
res.redirect('/login');
// 5. 파일 다운로드
res.download('/files/report.pdf');
// 6. 파일 전송
res.sendFile('/path/to/file.html');
// 7. 상태 코드만 보내기
res.sendStatus(204); // No Content
});
자주 사용하는 상태 코드
200
: 성공201
: 생성 성공 (POST에서 사용)204
: 성공했지만 보낼 내용 없음 (DELETE에서 사용)400
: 잘못된 요청401
: 인증 필요403
: 권한 없음404
: 찾을 수 없음500
: 서버 에러
6. 미들웨어 – Express의 진짜 힘
미들웨어는 Express의 핵심입니다. Express 앱은 사실상 미들웨어 함수들의 연속이라고 봐도 됩니다.
미들웨어가 뭔가요?
요청이 서버에 도착해서 응답이 나가기까지의 중간 과정에서 실행되는 함수들입니다. 공항 보안 검색대를 생각해보세요. 짐 검사, 신분증 확인, 금속 탐지기 등을 차례로 거치잖아요? 미들웨어도 똑같습니다.
실제로 뭐에 쓸까요?
- 모든 요청 로깅 (누가, 언제, 어떤 페이지를 요청했는지)
- 사용자 인증 (로그인했는지 확인)
- 데이터 파싱 (JSON이나 폼 데이터를 읽을 수 있게 변환)
- 에러 처리 (문제가 생겼을 때 일관되게 처리)
- CORS 설정 (다른 도메인에서의 요청 허용)
- 보안 헤더 추가
기본 미들웨어 작성
const express = require('express');
const app = express();
// 1. 로깅 미들웨어
app.use((req, res, next) => {
console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
next(); // 반드시 호출해야 다음으로 넘어감
});
// 2. JSON 파싱 미들웨어 (필수!)
app.use(express.json());
// 3. URL 인코딩된 데이터 파싱 (폼 데이터)
app.use(express.urlencoded({ extended: true }));
// 4. 정적 파일 제공 (HTML, CSS, 이미지 등)
app.use(express.static('public'));
app.get('/', (req, res) => {
res.send('홈페이지입니다');
});
app.listen(3000);
express.json()과 express.urlencoded()의 차이
// express.json() - API에서 JSON 데이터를 받을 때
// Content-Type: application/json
// { "name": "김철수", "age": 25 }
app.use(express.json());
// express.urlencoded() - HTML 폼에서 데이터를 받을 때
// Content-Type: application/x-www-form-urlencoded
// name=김철수&age=25
app.use(express.urlencoded({ extended: true }));
정적 파일 제공하기
HTML, CSS, 이미지, JavaScript 파일 등을 제공할 때 사용합니다:
const express = require('express');
const path = require('path');
const app = express();
// public 폴더의 파일들을 제공
app.use(express.static('public'));
// 가상 경로 설정
app.use('/static', express.static('public'));
// 절대 경로 사용 (권장)
app.use(express.static(path.join(__dirname, 'public')));
폴더 구조:
my-express-app/
├── public/
│ ├── css/
│ │ └── style.css
│ ├── js/
│ │ └── app.js
│ └── images/
│ └── logo.png
└── app.js
이제 http://localhost:3000/css/style.css
로 파일에 접근할 수 있습니다.
인증 미들웨어 예제
// 로그인 확인 미들웨어
const checkAuth = (req, res, next) => {
if (req.headers.authorization) {
next(); // 인증 통과
} else {
res.status(401).json({ error: '로그인이 필요합니다' });
}
};
// 특정 라우트에만 적용
app.get('/api/profile', checkAuth, (req, res) => {
res.json({ name: '김철수', email: 'kim@example.com' });
});
주의할 점
- 미들웨어는 순서대로 실행됩니다
next()
를 꼭 호출해야 다음 미들웨어로 넘어갑니다next()
를 안 부르면 요청이 멈춰버립니다- 에러 처리 미들웨어는 반드시 마지막에 위치해야 합니다
7. 라우팅과 REST API – 실제 예제로 배우기
라우팅은 URL과 HTTP 메서드(GET, POST, PUT, DELETE)에 따라 다른 응답을 보내는 것입니다.
기본 라우팅
const express = require('express');
const app = express();
app.use(express.json());
// GET: 데이터 조회
app.get('/users', (req, res) => {
res.send('사용자 목록');
});
// POST: 새 데이터 생성
app.post('/users', (req, res) => {
res.send('새 사용자 생성');
});
// PUT: 데이터 수정
app.put('/users/:id', (req, res) => {
res.send(`사용자 ${req.params.id} 수정`);
});
// DELETE: 데이터 삭제
app.delete('/users/:id', (req, res) => {
res.send(`사용자 ${req.params.id} 삭제`);
});
app.listen(3000);
동적 라우팅 – URL에서 값 받기
// URL 파라미터 사용
app.get('/users/:userId/posts/:postId', (req, res) => {
const { userId, postId } = req.params;
res.send(`사용자 ${userId}의 게시글 ${postId}`);
});
// 쿼리 파라미터 사용
app.get('/search', (req, res) => {
const { keyword, page = 1 } = req.query;
res.send(`검색어: ${keyword}, 페이지: ${page}`);
});
// 접속: /search?keyword=express&page=2
완전한 REST API 예제
const express = require('express');
const app = express();
app.use(express.json());
// 임시 데이터베이스
let users = [
{ id: 1, name: '김철수', email: 'kim@example.com' },
{ id: 2, name: '이영희', email: 'lee@example.com' }
];
// 모든 사용자 조회
app.get('/api/users', (req, res) => {
res.json(users);
});
// 특정 사용자 조회
app.get('/api/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ error: '사용자를 찾을 수 없습니다' });
}
res.json(user);
});
// 새 사용자 추가
app.post('/api/users', (req, res) => {
const newUser = {
id: users.length + 1,
name: req.body.name,
email: req.body.email
};
users.push(newUser);
res.status(201).json(newUser);
});
// 사용자 정보 수정
app.put('/api/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ error: '사용자를 찾을 수 없습니다' });
}
user.name = req.body.name || user.name;
user.email = req.body.email || user.email;
res.json(user);
});
// 사용자 삭제
app.delete('/api/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: '사용자를 찾을 수 없습니다' });
}
users.splice(index, 1);
res.status(204).send();
});
app.listen(3000, () => {
console.log('API 서버가 3000번 포트에서 실행 중입니다');
});
API 테스트하기
API를 만들었으면 테스트해봐야겠죠? 브라우저로는 GET만 테스트할 수 있어서, 전문 도구를 사용합니다:
- Postman (postman.com): 가장 유명하고 기능이 많음
- Thunder Client: VS Code 확장 프로그램, 가볍고 편함
- curl: 터미널에서 사용
# curl 사용 예제
# GET 요청
curl http://localhost:3000/api/users
# POST 요청
curl -X POST http://localhost:3000/api/users \
-H "Content-Type: application/json" \
-d '{"name":"박민수","email":"park@example.com"}'
# PUT 요청
curl -X PUT http://localhost:3000/api/users/1 \
-H "Content-Type: application/json" \
-d '{"name":"김철수(수정)","email":"kim_new@example.com"}'
# DELETE 요청
curl -X DELETE http://localhost:3000/api/users/1
8. 코드 정리하기 – Router와 프로젝트 구조
프로젝트가 커지면 한 파일에 모든 라우트를 작성하기 힘듭니다. Router를 사용하면 기능별로 파일을 나눌 수 있습니다.
권장 프로젝트 구조
my-express-app/
├── src/
│ ├── routes/ # 라우트 정의
│ │ ├── users.js
│ │ └── posts.js
│ ├── controllers/ # 비즈니스 로직
│ │ ├── userController.js
│ │ └── postController.js
│ ├── middleware/ # 커스텀 미들웨어
│ │ ├── auth.js
│ │ └── errorHandler.js
│ ├── models/ # 데이터 모델
│ │ └── User.js
│ └── utils/ # 유틸리티 함수
│ └── validator.js
├── public/ # 정적 파일
│ ├── css/
│ ├── js/
│ └── images/
├── .env # 환경 변수
├── .gitignore
├── app.js # 메인 파일
└── package.json
routes/users.js
const express = require('express');
const router = express.Router();
// GET /api/users
router.get('/', (req, res) => {
res.json({ message: '사용자 목록' });
});
// GET /api/users/:id
router.get('/:id', (req, res) => {
res.json({ message: `사용자 ${req.params.id} 상세 정보` });
});
// POST /api/users
router.post('/', (req, res) => {
res.status(201).json({ message: '새 사용자 생성' });
});
module.exports = router;
app.js
const express = require('express');
const usersRouter = require('./routes/users');
const postsRouter = require('./routes/posts');
const app = express();
// 미들웨어
app.use(express.json());
app.use(express.static('public'));
// 라우터 연결
app.use('/api/users', usersRouter);
app.use('/api/posts', postsRouter);
// 404 처리
app.use((req, res) => {
res.status(404).json({ error: '페이지를 찾을 수 없습니다' });
});
// 에러 처리
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: '서버 에러가 발생했습니다' });
});
app.listen(3000, () => {
console.log('서버가 3000번 포트에서 실행 중입니다');
});
9. 에러 처리와 디버깅
실제 서비스에서는 에러가 필연적으로 발생합니다. 제대로 처리하지 않으면 서버가 죽어버립니다.
에러 처리 미들웨어
const express = require('express');
const app = express();
// 일반 라우트
app.get('/', (req, res) => {
res.send('정상 동작');
});
app.get('/error', (req, res) => {
throw new Error('의도적인 에러!');
});
// 404 에러 처리 (라우트가 없을 때)
app.use((req, res, next) => {
res.status(404).json({ error: '페이지를 찾을 수 없습니다' });
});
// 에러 처리 미들웨어 (반드시 마지막에!)
app.use((err, req, res, next) => {
console.error(err.stack);
// 개발 환경에서는 상세 에러 메시지, 운영에서는 숨김
const errorMessage = process.env.NODE_ENV === 'development'
? err.message
: '서버 에러가 발생했습니다';
res.status(err.status || 500).json({ error: errorMessage });
});
app.listen(3000);
Express 5의 개선된 에러 처리
Express 5부터는 async/await 에러를 자동으로 잡아줍니다:
// Express 5에서는 try-catch 없이도 자동으로 에러 처리
app.get('/user/:id', async (req, res) => {
const user = await db.findUser(req.params.id); // 에러나면 자동으로 에러 핸들러로
res.json(user);
});
디버깅 팁
- console.log 활용
app.use((req, res, next) => {
console.log('=== 요청 정보 ===');
console.log('Method:', req.method);
console.log('URL:', req.url);
console.log('Body:', req.body);
console.log('=================');
next();
});
- VS Code 디버거 사용
.vscode/launch.json
생성:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Express 디버그",
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/app.js"
}
]
}
이제 F5를 눌러 디버그 모드로 실행하고, 브레이크포인트를 설정할 수 있습니다.
10. 실전 팁 – 프로덕션 환경 준비하기
환경 변수 관리
npm install dotenv
.env
파일:
NODE_ENV=development
PORT=3000
DATABASE_URL=mongodb://localhost:27017/myapp
JWT_SECRET=your-secret-key-here
API_KEY=your-api-key
.gitignore
에 .env
추가 (중요!):
node_modules/
.env
app.js에서 사용:
require('dotenv').config();
const port = process.env.PORT || 3000;
const dbUrl = process.env.DATABASE_URL;
const jwtSecret = process.env.JWT_SECRET;
보안 강화
npm install helmet cors express-rate-limit
const helmet = require('helmet');
const cors = require('cors');
const rateLimit = require('express-rate-limit');
// 보안 헤더 설정
app.use(helmet());
// CORS 설정
const corsOptions = {
origin: ['http://localhost:3000', 'https://yourdomain.com'], // 허용할 도메인
credentials: true, // 쿠키 전송 허용
optionsSuccessStatus: 200
};
app.use(cors(corsOptions));
// API 호출 제한 (DDoS 방어)
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15분
max: 100, // IP당 최대 100번 요청
message: '너무 많은 요청을 보냈습니다. 나중에 다시 시도해주세요.'
});
app.use('/api/', limiter);
로깅 설정
npm install morgan
const morgan = require('morgan');
// 개발 환경: 간단한 로그
if (process.env.NODE_ENV === 'development') {
app.use(morgan('dev'));
}
// 운영 환경: 상세한 로그
if (process.env.NODE_ENV === 'production') {
app.use(morgan('combined'));
}
입력 값 검증
npm install joi
const Joi = require('joi');
// 사용자 생성 시 검증
app.post('/api/users', (req, res) => {
const schema = Joi.object({
name: Joi.string().min(2).max(30).required(),
email: Joi.string().email().required(),
age: Joi.number().integer().min(0).max(120)
});
const { error, value } = schema.validate(req.body);
if (error) {
return res.status(400).json({ error: error.details[0].message });
}
// 검증 통과한 데이터 사용
res.json({ message: '생성 성공', user: value });
});
11. Express 5의 주요 변경사항
2024년 10월 Express 5.0이 10년 만에 출시되었습니다:
- Node.js 18 이상 필수: 최신 JavaScript 기능 사용 가능
- 자동 에러 처리: async/await 에러를 자동으로 잡아줌
- 더 엄격한 경로 매칭:
/foo*
→/foo(.*)
로 변경 필요 - 성능 개선: 레거시 코드 제거로 더 빨라짐
- 새로운 기능: res.send()에서 Uint8Array 지원 등
대부분의 Express 4 코드는 큰 수정 없이 그대로 동작하지만, 자세한 내용은 마이그레이션 가이드를 참고하세요.
12. 다음 단계 – 더 배워야 할 것들
Express 기본을 익혔다면 이제 다음으로 나아갈 차례입니다:
데이터베이스 연결
- MongoDB + Mongoose: NoSQL, 빠르게 시작하기 좋음
- PostgreSQL + Prisma: 관계형 DB, 복잡한 쿼리에 강함
- MySQL + Sequelize: 가장 널리 사용됨
인증 구현
- JWT: 토큰 기반 인증, API에 적합
- Passport.js: 소셜 로그인 (Google, Facebook 등)
- bcrypt: 비밀번호 암호화
프론트엔드 연결
- React: 가장 인기 있는 선택
- Vue: 배우기 쉬움
- Angular: 대규모 프로젝트에 적합
테스팅
- Jest: 단위 테스트
- Supertest: API 엔드포인트 테스트
- Mocha + Chai: 전통적인 테스트 도구
배포
- Docker: 컨테이너화
- PM2: 프로세스 관리 (무중단 재시작, 로드 밸런싱)
- Nginx: 리버스 프록시
- 클라우드: AWS, Heroku, Render, Vercel
Express.js는 처음엔 낯설지만, 한번 익숙해지면 정말 편리한 도구입니다. JavaScript 하나로 프론트엔드부터 백엔드까지 개발할 수 있다는 건 큰 장점이고, 이게 바로 MERN 스택이 인기 있는 이유입니다.
추천 자료
- Express 공식 문서 – 가장 정확한 정보
- MDN Express 튜토리얼 – 체계적인 학습
- npm Express 페이지 – 버전 정보와 API 레퍼런스
Express는 15년 가까이 개발자들의 신뢰를 받아온 검증된 프레임워크입니다. 빠르게 변하는 트렌드 속에서도 여전히 1위를 지키는 이유는, 단순히 먼저 나왔기 때문이 아니라 실용적이고 안정적이며 생산성 높은 도구이기 때문입니다. 🙂