React Native + Express.js 프로젝트의 Git 저장소 구성 가이드

2025. 8. 22. 23:36·개발

React Native(Expo)로 프론트엔드 앱을 개발하고 Express.js로 백엔드 서버를 구축할 때, Git 저장소를 어떻게 구성할지는 중요한 결정사항입니다. 이 글에서는 다양한 접근법과 현재 업계 트렌드, 그리고 Monorepo에 대해 자세히 알아보겠습니다.

Git 저장소 구성 방법

1. Monorepo (단일 저장소)

Monorepo는 여러 프로젝트를 하나의 Git 저장소에서 관리하는 방식입니다.

my-app/
├── frontend/          # React Native/Expo 앱
│   ├── package.json
│   ├── App.js
│   └── ...
├── backend/           # Express.js 서버
│   ├── package.json
│   ├── server.js
│   └── ...
├── shared/            # 공유 코드 (타입, 유틸리티 등)
└── package.json       # 루트 패키지.json

장점

  • 코드 공유가 용이하여 타입 정의나 유틸리티 함수를 쉽게 재사용할 수 있습니다
  • 프론트엔드와 백엔드의 버전 관리가 동기화됩니다
  • 한 번의 클론으로 전체 프로젝트를 설정할 수 있습니다
  • CI/CD 파이프라인을 단순화할 수 있습니다

단점

  • 프로젝트가 커질수록 저장소 크기가 증가합니다
  • 팀이 커지면 권한 관리가 복잡해질 수 있습니다
  • 전체 프로젝트의 빌드 시간이 증가할 가능성이 있습니다

2. Multi-repo (분리된 저장소)

각 프로젝트를 별도의 저장소로 관리하는 전통적인 방식입니다.

my-app-frontend/       # 별도 저장소
├── package.json
├── App.js
└── ...

my-app-backend/        # 별도 저장소
├── package.json
├── server.js
└── ...

장점

  • 팀별로 독립적인 개발이 가능합니다
  • 세밀한 권한 관리가 가능합니다
  • 각 저장소의 크기를 최적화할 수 있습니다
  • 독립적인 배포가 가능합니다

단점

  • 코드 공유가 어렵습니다
  • 버전 동기화가 복잡합니다
  • 개발 환경 설정이 번거로울 수 있습니다

3. Hybrid 접근법

최근 트렌드는 Monorepo와 워크스페이스를 결합한 접근법입니다.

{
  "name": "my-app",
  "workspaces": [
    "packages/mobile",
    "packages/server",
    "packages/shared"
  ],
  "scripts": {
    "dev": "concurrently \"npm run dev:server\" \"npm run dev:mobile\"",
    "dev:server": "npm run dev --workspace=packages/server",
    "dev:mobile": "npm run start --workspace=packages/mobile"
  }
}

Monorepo 심화 이해

Monorepo란 무엇인가

Monorepo(Monolithic Repository)는 여러 개의 프로젝트나 패키지를 하나의 Git 저장소에서 관리하는 방식입니다. 이는 각 프로젝트마다 별도 저장소를 사용하는 Multi-repo와 대비되는 개념입니다.

전통적인 Multi-repo

github.com/yourname/my-app-frontend  (저장소 1)
github.com/yourname/my-app-backend   (저장소 2)
github.com/yourname/my-app-shared    (저장소 3)

Monorepo

github.com/yourname/my-app  (저장소 1개)
├── packages/
│   ├── mobile/     (React Native 앱)
│   ├── server/     (Express.js 서버)
│   └── shared/     (공통 코드)

실제 구현 방법

폴더 구조

my-app/
├── package.json                 # 루트 설정
├── packages/
│   ├── mobile/                  # React Native/Expo
│   │   ├── package.json
│   │   ├── App.tsx
│   │   ├── app.json
│   │   └── src/
│   ├── server/                  # Express.js
│   │   ├── package.json
│   │   ├── server.js
│   │   └── src/
│   └── shared/                  # 공통 코드
│       ├── package.json
│       ├── types/               # TypeScript 타입
│       ├── utils/               # 유틸리티 함수
│       └── constants/           # 상수
├── tools/                       # 빌드/배포 스크립트
└── docs/                        # 문서

루트 package.json 설정

{
  "name": "my-app",
  "private": true,
  "workspaces": [
    "packages/*"
  ],
  "scripts": {
    "dev": "concurrently \"npm run dev:server\" \"npm run dev:mobile\"",
    "dev:server": "npm run dev --workspace=packages/server",
    "dev:mobile": "npm run start --workspace=packages/mobile",
    "build": "npm run build --workspaces",
    "test": "npm run test --workspaces",
    "lint": "eslint packages/*/src --ext .ts,.tsx,.js,.jsx",
    "install:all": "npm install"
  },
  "devDependencies": {
    "concurrently": "^7.6.0",
    "eslint": "^8.0.0",
    "@typescript-eslint/eslint-plugin": "^5.0.0"
  }
}

공유 코드 활용 예시

공통 타입 정의

// packages/shared/types/api.ts
export interface User {
  id: string;
  email: string;
  name: string;
  createdAt: Date;
}

export interface LoginRequest {
  email: string;
  password: string;
}

export interface ApiResponse<T> {
  success: boolean;
  data?: T;
  error?: string;
}

공통 상수

// packages/shared/constants/api.ts
export const API_ENDPOINTS = {
  LOGIN: '/auth/login',
  USERS: '/users',
  POSTS: '/posts'
} as const;

export const API_BASE_URL = 
  process.env.NODE_ENV === 'production' 
    ? 'https://api.myapp.com'
    : 'http://localhost:3000';

서버에서 공유 코드 사용

// packages/server/src/routes/auth.js
import { API_ENDPOINTS } from '@myapp/shared/constants/api';
import { User, LoginRequest } from '@myapp/shared/types/api';

app.post(API_ENDPOINTS.LOGIN, (req, res) => {
  const loginData = req.body;
  // 로그인 로직...
  
  const user = {
    id: '123',
    email: loginData.email,
    name: 'John Doe',
    createdAt: new Date()
  };
  
  res.json({ success: true, data: user });
});

모바일 앱에서 공유 코드 사용

// packages/mobile/src/services/api.ts
import { API_BASE_URL, API_ENDPOINTS } from '@myapp/shared/constants/api';
import { User, LoginRequest, ApiResponse } from '@myapp/shared/types/api';

export const authAPI = {
  login: async (credentials: LoginRequest): Promise<ApiResponse<User>> => {
    const response = await fetch(`${API_BASE_URL}${API_ENDPOINTS.LOGIN}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(credentials)
    });
    return response.json();
  }
};

Monorepo의 실제 이점

타입 안정성 서버에서 API 응답 타입을 변경하면, 모바일 앱에서 즉시 타입 에러가 발생하여 변경사항을 쉽게 감지할 수 있습니다.

코드 재사용

// 공통 유틸리티
export const formatDate = (date: Date) => {
  return date.toLocaleDateString('ko-KR');
};

export const validateEmail = (email: string) => {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
};

일관된 개발 환경 루트에서 모든 패키지의 ESLint, Prettier 설정을 통일할 수 있습니다.

주요 Monorepo 도구들

npm/yarn workspaces

# 설치
npm install

# 특정 패키지에 의존성 추가
npm install lodash --workspace=packages/server

# 모든 패키지 빌드
npm run build --workspaces

Lerna

npm install -g lerna
lerna init
lerna add lodash --scope=@myapp/server
lerna run build

Nx

npx create-nx-workspace@latest myapp
nx generate @nrwl/react-native:app mobile
nx generate @nrwl/express:app server
nx run mobile:start

현재 업계 트렌드

2024년부터 2025년 현재까지의 주요 트렌드는 다음과 같습니다.

Monorepo가 주류 특히 스타트업과 중소 규모 팀에서 Monorepo 채택이 증가하고 있습니다.

도구의 발전 Nx, Lerna, Rush 등 Monorepo 관리 도구들이 성숙해졌습니다.

TypeScript 공유 프론트엔드와 백엔드 간 타입 공유의 중요도가 높아졌습니다.

pnpm 워크스페이스 성능상의 이유로 npm이나 yarn 대신 pnpm을 선택하는 경우가 증가하고 있습니다.

추천사항

초기 개발 단계 (1-3명 팀) Monorepo를 추천합니다. 코드 공유와 빠른 개발이 우선순위이며, TypeScript 사용 시 타입 공유의 이점이 큽니다.

성장 단계 (4명 이상) 팀 구조와 배포 주기에 따라 결정하되, 마이크로서비스 아키텍처를 고려한다면 Multi-repo도 검토해볼 만합니다.

추천 도구 스택

  • Monorepo 관리: pnpm workspaces 또는 Nx
  • 공유 코드: TypeScript + 공통 타입 정의
  • 개발 환경: Docker Compose (로컬 개발)

실제 사용 사례

Google, Facebook/Meta, Microsoft, Uber, Twitter 등 많은 대기업들이 Monorepo 방식을 채택하고 있습니다. 특히 React Native와 Node.js 조합에서는 코드 공유의 이점이 매우 큽니다.

시작하기

Monorepo 구조로 시작하려면 다음과 같이 진행할 수 있습니다.

# 1. 프로젝트 초기화
mkdir my-app && cd my-app
npm init -y

# 2. 워크스페이스 설정
# package.json에 "workspaces": ["packages/*"] 추가

# 3. 패키지 폴더 생성
mkdir -p packages/mobile packages/server packages/shared

# 4. 각 패키지 초기화
cd packages/mobile && npx create-expo-app . --template typescript
cd ../server && npm init -y
cd ../shared && npm init -y

# 5. 루트에서 모든 의존성 설치
cd ../../ && npm install

결론

React Native + Express.js 프로젝트에서는 Monorepo 방식이 많은 이점을 제공합니다. 특히 API 타입 공유, 공통 비즈니스 로직 재사용, 일관된 개발 환경 구성 등의 장점이 있습니다. 소규모 프로젝트에서는 설정이 간단하며, 프로젝트가 성장해도 확장하기 좋은 구조입니다.

프로젝트의 규모와 팀 구성에 따라 최적의 선택은 달라질 수 있지만, 현재 업계 트렌드와 실제 이점을 고려할 때 Monorepo는 충분히 검토해볼 만한 접근법입니다.

'개발' 카테고리의 다른 글

React Native + Express.js 개발 필수 도구 완벽 가이드  (0) 2025.08.23
Monorepo 도구 완전 가이드: 초보자를 위한 npm workspaces, Lerna, Nx 비교  (0) 2025.08.22
React Native/Expo 개발, 로컬 서버 연결 실패? 원인부터 해결까지  (0) 2025.08.22
Expo 완전 마스터 가이드 - 개발부터 배포까지  (0) 2025.08.20
React 웹 프로젝트를 Expo React Native로 완전 마이그레이션하기: 실전 가이드  (4) 2025.08.09
'개발' 카테고리의 다른 글
  • React Native + Express.js 개발 필수 도구 완벽 가이드
  • Monorepo 도구 완전 가이드: 초보자를 위한 npm workspaces, Lerna, Nx 비교
  • React Native/Expo 개발, 로컬 서버 연결 실패? 원인부터 해결까지
  • Expo 완전 마스터 가이드 - 개발부터 배포까지
5jyan5
5jyan5
  • 5jyan5
    jyan
    5jyan5
  • 전체
    오늘
    어제
    • 분류 전체보기 (242)
      • 김영한의 스프링 핵심 원리(기본편) (8)
      • 김영한의 스프링 핵심 원리 - 고급편 (11)
      • 김영한의 스프링 MVC 1편 (1)
      • 김영한의 스프링 DB 1편 (3)
      • 김영한의 스프링 MVC 2편 (3)
      • 김영한의 ORM 표준 JPA 프로그래밍(기본편) (9)
      • 김영한의 스프링 부트와 JPA 활용2 (2)
      • 김영한의 실전 자바 - 중급 1편 (1)
      • 김영한의 실전 자바 - 고급 1편 (9)
      • 김영한의 실전 자바 - 고급 2편 (9)
      • Readable Code: 읽기 좋은 코드를 작성.. (2)
      • 김영한의 실전 자바 - 고급 3편 (9)
      • CKA (118)
      • 개발 (37)
      • 경제 (4)
      • 리뷰 (1)
      • 정보 (2)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      Thread
      WAS
      gesingleresult
      Target
      페치 조인
      락
      김영한
      log trace
      버퍼
      자바
      jdk 동적 프록시
      requset scope
      프록시
      고급
      @discriminatorcolumn
      jpq
      hibernate5module
      @within
      조회 성능 최적화
      프록시 팩토리
      JPQL
      빈 후처리기
      @args
      typequery
      스레드
      @discriminatorvalue
      reentarantlock
      양방향 맵핑
      cglib
      단방향 맵핑
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.2
    5jyan5
    React Native + Express.js 프로젝트의 Git 저장소 구성 가이드
    상단으로

    티스토리툴바