React + Node.js 풀스택 앱 배포하기 – 완성까지 한번에!

React + Node.js 풀스택 앱 배포하기 – 완성까지 한번에!

프로젝트 소개 및 목표

React + Node.js 풀스택 앱 배포하기는 프론트엔드부터 백엔드, 그리고 실제 서버 배포까지 전 과정을 경험할 수 있는 실무 중심 프로젝트입니다. 이 가이드를 통해 React로 사용자 인터페이스를 구축하고, Node.js와 Express로 RESTful API를 개발하며, MongoDB를 활용한 데이터 관리, 그리고 AWS나 Heroku를 통한 실제 배포까지 완성할 수 있습니다. 풀스택 개발자로서 필요한 핵심 역량을 모두 습득하며, 포트폴리오에 추가할 수 있는 완성도 높은 프로젝트를 만들어보세요. 초보자도 따라할 수 있도록 단계별로 상세하게 설명하며, 실무에서 바로 활용 가능한 베스트 프랙티스를 적용합니다.

필요한 기술 스택

이 프로젝트를 완성하기 위해 다음 기술들이 필요합니다:

  • 프론트엔드: React 18+, React Router, Axios, Tailwind CSS 또는 Material-UI
  • 백엔드: Node.js 18+, Express.js, JWT 인증, bcrypt
  • 데이터베이스: MongoDB Atlas (클라우드) 또는 PostgreSQL
  • 배포: Vercel (프론트엔드), Railway/Render (백엔드), Docker (선택사항)
  • 개발도구: Git, Postman, VS Code, npm/yarn

Node.js와 npm이 설치되어 있어야 하며, Git을 통한 버전 관리 기본 지식이 있으면 도움이 됩니다.

프로젝트 셋업

먼저 프로젝트 폴더 구조를 설정합니다. 루트 폴더에 client(React)와 server(Node.js) 폴더를 분리하여 관리합니다.

# 프로젝트 루트 폴더 생성
mkdir fullstack-app && cd fullstack-app

# 백엔드 설정
mkdir server && cd server
npm init -y
npm install express mongoose cors dotenv jsonwebtoken bcryptjs
npm install --save-dev nodemon

# 프론트엔드 설정
cd ..
npx create-react-app client
cd client
npm install axios react-router-dom

package.json에 개발 스크립트를 추가하여 동시 실행이 가능하도록 설정합니다. concurrently 패키지를 사용하면 한 번의 명령으로 프론트엔드와 백엔드를 동시에 실행할 수 있습니다.

# 루트 폴더에서
npm install --save-dev concurrently

단계별 구현 과정

1단계: 백엔드 API 서버 구축

Express 서버를 설정하고 기본 라우팅을 구현합니다. server/index.js 파일을 생성합니다:

const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
require('dotenv').config();

const app = express();

// 미들웨어
app.use(cors());
app.use(express.json());

// MongoDB 연결
mongoose.connect(process.env.MONGODB_URI, {
  useNewUrlParser: true,
  useUnifiedTopology: true
})
.then(() => console.log('MongoDB 연결 성공'))
.catch(err => console.error('MongoDB 연결 실패:', err));

// 라우트
app.get('/api/health', (req, res) => {
  res.json({ status: 'OK', message: '서버가 정상 작동 중입니다' });
});

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
  console.log(`서버가 포트 ${PORT}에서 실행 중입니다`);
});

2단계: 사용자 인증 시스템 구현

JWT 기반 인증을 구현합니다. server/models/User.js에 사용자 모델을 생성합니다:

const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const userSchema = new mongoose.Schema({
  username: {
    type: String,
    required: true,
    unique: true,
    trim: true
  },
  email: {
    type: String,
    required: true,
    unique: true,
    lowercase: true
  },
  password: {
    type: String,
    required: true,
    minlength: 6
  }
}, { timestamps: true });

// 비밀번호 해싱 미들웨어
userSchema.pre('save', async function(next) {
  if (!this.isModified('password')) return next();
  this.password = await bcrypt.hash(this.password, 10);
  next();
});

// 비밀번호 검증 메서드
userSchema.methods.comparePassword = async function(candidatePassword) {
  return await bcrypt.compare(candidatePassword, this.password);
};

module.exports = mongoose.model('User', userSchema);

server/routes/auth.js에 인증 라우트를 구현합니다:

const express = require('express');
const jwt = require('jsonwebtoken');
const User = require('../models/User');

const router = express.Router();

// 회원가입
router.post('/register', async (req, res) => {
  try {
    const { username, email, password } = req.body;
    
    const existingUser = await User.findOne({ $or: [{ email }, { username }] });
    if (existingUser) {
      return res.status(400).json({ message: '이미 존재하는 사용자입니다' });
    }

    const user = new User({ username, email, password });
    await user.save();

    const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, {
      expiresIn: '7d'
    });

    res.status(201).json({ token, user: { id: user._id, username, email } });
  } catch (error) {
    res.status(500).json({ message: '서버 오류가 발생했습니다', error: error.message });
  }
});

// 로그인
router.post('/login', async (req, res) => {
  try {
    const { email, password } = req.body;
    
    const user = await User.findOne({ email });
    if (!user || !(await user.comparePassword(password))) {
      return res.status(401).json({ message: '이메일 또는 비밀번호가 잘못되었습니다' });
    }

    const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, {
      expiresIn: '7d'
    });

    res.json({ token, user: { id: user._id, username: user.username, email } });
  } catch (error) {
    res.status(500).json({ message: '서버 오류가 발생했습니다', error: error.message });
  }
});

module.exports = router;

3단계: React 프론트엔드 구축

React 앱에서 API와 통신하는 기능을 구현합니다. client/src/services/api.js를 생성합니다:

import axios from 'axios';

const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:5000/api';

const api = axios.create({
  baseURL: API_URL,
  headers: {
    'Content-Type': 'application/json'
  }
});

// 요청 인터셉터: 토큰 자동 추가
api.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// 응답 인터셉터: 에러 처리
api.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      localStorage.removeItem('token');
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

export const authAPI = {
  register: (userData) => api.post('/auth/register', userData),
  login: (credentials) => api.post('/auth/login', credentials)
};

export default api;

client/src/components/Login.js에 로그인 컴포넌트를 생성합니다:

import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { authAPI } from '../services/api';

function Login() {
  const [formData, setFormData] = useState({ email: '', password: '' });
  const [error, setError] = useState('');
  const navigate = useNavigate();

  const handleSubmit = async (e) => {
    e.preventDefault();
    setError('');

    try {
      const response = await authAPI.login(formData);
      localStorage.setItem('token', response.data.token);
      localStorage.setItem('user', JSON.stringify(response.data.user));
      navigate('/dashboard');
    } catch (err) {
      setError(err.response?.data?.message || '로그인에 실패했습니다');
    }
  };

  return (
    

로그인

{error && (
{error}
)}
setFormData({ ...formData, email: e.target.value })} required />
setFormData({ ...formData, password: e.target.value })} required />
); } export default Login;

4단계: 환경 변수 설정

server/.env 파일을 생성하여 환경 변수를 설정합니다:

MONGODB_URI=mongodb+srv://username:[email protected]/myapp
JWT_SECRET=your-super-secret-jwt-key-change-this
PORT=5000
NODE_ENV=development

client/.env 파일도 생성합니다:

REACT_APP_API_URL=http://localhost:5000/api

테스트 및 배포

로컬 테스트

React + Node.js 풀스택 앱 배포하기 전에 로컬에서 충분히 테스트해야 합니다. 루트 폴더의 package.json에 다음 스크립트를 추가합니다:

{
  "scripts": {
    "server": "cd server && nodemon index.js",
    "client": "cd client && npm start",
    "dev": "concurrently \"npm run server\" \"npm run client\""
  }
}

터미널에서 npm run dev를 실행하여 프론트엔드와 백엔드를 동시에 실행합니다.

프로덕션 배포

백엔드 배포 (Railway/Render):

  1. GitHub에 코드를 푸시합니다
  2. Railway 또는 Render에 가입하고 새 프로젝트를 생성합니다
  3. GitHub 저장소를 연결하고 server 폴더를 루트로 설정합니다
  4. 환경 변수(MONGODB_URI, JWT_SECRET)를 설정합니다
  5. 자동 배포가 완료되면 API URL을 확인합니다

프론트엔드 배포 (Vercel):

  1. Vercel에 가입하고 GitHub 저장소를 연결합니다
  2. Root Directory를 ‘client’로 설정합니다
  3. 환경 변수 REACT_APP_API_URL에 배포된 백엔드 URL을 설정합니다
  4. Deploy 버튼을 클릭하여 배포를 시작합니다

배포 후에는 CORS 설정을 확인하고, 프로덕션 환경에서 모든 기능이 정상 작동하는지 테스트합니다.

마무리 및 확장 아이디어

이제 React + Node.js 풀스택 앱 배포하기 프로젝트가 완성되었습니다! 이 프로젝트를 통해 프론트엔드와 백엔드 개발, 데이터베이스 연동, 인증 시스템 구축, 그리고 실제 배포까지 전체 개발 사이클을 경험했습니다. 추가로 구현해볼 수 있는 기능들로는 소셜 로그인(Google, GitHub OAuth), 파일 업로드(AWS S3, Cloudinary), 실시간 채팅(Socket.io), 이메일 인증, 비밀번호 재설정, 프로필 관리, 관리자 대시보드 등이 있습니다. CI/CD 파이프라인을 구축하고 Docker로 컨테이너화하면 더욱 전문적인 프로젝트가 됩니다. 이 프로젝트를 GitHub에 공개하고 README를 작성하여 포트폴리오로 활용하세요!

📚 함께 읽으면 좋은 글

1

React + Node.js 풀스택 앱 배포하기 – 완성까지 한번에!

📂 프로젝트 아이디어
📅 2025. 11. 20.
🎯 React + Node.js 풀스택 앱 배포하기

2

React + Node.js 풀스택 앱 배포하기 – 완성까지 한번에!

📂 프로젝트 아이디어
📅 2025. 11. 16.
🎯 React + Node.js 풀스택 앱 배포하기

3

React + Node.js 풀스택 앱 배포하기 – 완성까지 한번에!

📂 프로젝트 아이디어
📅 2025. 11. 15.
🎯 React + Node.js 풀스택 앱 배포하기

4

React + Node.js 풀스택 앱 배포하기 – 완성까지 한번에!

📂 프로젝트 아이디어
📅 2025. 11. 11.
🎯 React + Node.js 풀스택 앱 배포하기

5

React + Node.js 풀스택 앱 배포하기 – 완성까지 한번에!

📂 프로젝트 아이디어
📅 2025. 11. 11.
🎯 React + Node.js 풀스택 앱 배포하기

💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!

📢 이 글이 도움되셨나요? 공유해주세요!

여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨

🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏

💬 여러분의 소중한 의견을 들려주세요!

이 글을 읽고 새롭게 알게 된 정보가 있다면 공유해주세요!

💡
유용한 정보 공유

궁금한 점 질문

🤝
경험담 나누기

👍
의견 표현하기

⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨

🔔 블로그 구독하고 최신 글을 받아보세요!

📚
다양한 주제
17개 카테고리

정기 업데이트
하루 3회 발행

🎯
실용적 정보
바로 적용 가능

💡
최신 트렌드
2025년 기준

🌟 프로젝트 아이디어부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨

📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!

답글 남기기