Cloud & Platform Engineering
Windows에서 macOS로 Next.js 개발환경 안전하게 이전하기
Git 기준점과 비공개 파일을 보존하면서 Next.js 프로젝트를 Apple Silicon macOS 환경으로 이전하고 검증한 과정을 정리합니다.
개발 프로젝트를 다른 운영체제로 옮기는 일은 폴더 하나를 복사하는 것으로 끝나지 않는다. 소스 코드는 그대로 보여도 Git 메타데이터, 숨김 설정, 플랫폼별 네이티브 패키지, 로컬에서만 보관하던 비공개 파일이 빠지면 재현 가능한 개발환경이라고 보기 어렵다.
이 글은 Windows에서 사용하던 Next.js 15 프로젝트를 Apple Silicon 기반 macOS로 이전하면서 실제로 확인한 복구 순서를 정리한 기록이다. 목표는 단순히 개발 서버를 켜는 것이 아니라, 원격 저장소와 로컬 전용 자산을 함께 보존하고 CI와 동일한 Node.js 버전에서 전체 검증을 통과하는 것이었다.
먼저 이전 완료 조건을 정한다
파일을 옮긴 뒤 곧바로 npm install을 실행하면 눈앞의 오류는 해결할 수 있지만, 무엇이 사라졌는지 확인하기는 더 어려워진다. 먼저 이전 완료 조건을 체크리스트로 만들었다.
- 작업 볼륨이 쓰기 가능한 안정적인 파일시스템인지 확인한다.
.git,.gitignore, CI workflow 같은 숨김 경로가 보존됐는지 확인한다.- Git에 올라가지 않는 로컬 문서와 인프라 설정 파일의 존재 여부만 확인한다.
- CI에서 사용하는 Node.js 메이저 버전을 맞춘다.
- lockfile을 유지한 채 운영체제에 맞는 의존성을 다시 설치한다.
- 콘텐츠 감사, lint, typecheck, production build를 모두 실행한다.
여기서 중요한 점은 민감한 파일의 내용을 진단 로그에 출력하지 않는 것이다. 비공개 설정은 파일의 존재 여부와 ignore 상태만 확인해도 이전 검증에 충분하다.
숨김 파일 누락을 일반 파일 누락과 구분한다
복사된 프로젝트에는 package.json, src, content가 모두 있었지만 Git 저장소로 인식되지 않았다. 최상위 숨김 항목을 확인하니 .git뿐 아니라 .gitignore와 CI 설정도 빠져 있었다. 이는 개별 파일 문제가 아니라 복사 과정에서 숨김 항목 전체가 제외됐다는 신호다.
이 상태에서 새로 git init을 실행하면 기존 커밋 기록과 원격 추적 관계를 잃는다. 대신 원격 저장소를 별도 임시 경로에 clone하고 다음 항목을 기준점으로 확인했다.
git status --short --branch
git branch --show-current
git log -5 --oneline --decorate원격 HEAD가 이전 직전 기록과 일치한 뒤에만 복구 기준본으로 사용했다. 원격 기준 추적 파일을 현재 작업 폴더에 합칠 때는 삭제 옵션을 사용하지 않았다. 덕분에 원격에 존재하지 않는 비공개 작업 기록과 로컬 인프라 설정을 유지하면서 Git 기록과 추적 파일을 복구할 수 있었다.
덮어쓰기 전에 복구 지점을 만든다
원격이 기준본이라고 해도 현재 파일을 바로 덮어쓰는 것은 위험하다. 현재 복사본에서 원격의 추적 대상에 해당하는 파일만 임시 백업한 뒤 합치기를 진행했다.
Current project copy
├─ tracked-file backup
├─ ignored private files (preserved in place)
└─ remote baseline overlay (no delete)이 방식은 두 가지 위험을 줄인다.
- 운영체제 이전 중 내용이 달라진 추적 파일을 다시 비교할 수 있다.
- 원격에 없는 로컬 전용 파일을 clone 결과로 대체하거나 삭제하지 않는다.
복구 직후에는 브랜치, HEAD, origin/main, 최근 커밋을 다시 확인했다. 줄바꿈 변환으로 대량 변경이 생기지 않도록 저장소 로컬 설정도 core.autocrlf=input으로 맞췄다.
Node.js 버전과 네이티브 패키지를 다시 맞춘다
Windows의 node_modules를 macOS로 복사하면 안 된다. Next.js의 SWC와 이미지 처리 라이브러리인 Sharp는 운영체제와 CPU 아키텍처에 맞는 바이너리를 사용하기 때문이다.
CI와 동일한 Node.js 22를 설치한 뒤 기존 package-lock.json을 유지하면서 다음 명령을 실행했다.
npm ci설치 후에는 Apple Silicon용 SWC와 macOS용 Sharp가 선택됐는지 확인했다. lockfile을 임의로 다시 만들거나 Windows 바이너리를 수동 복구하지 않았다.
의존성 audit에서 보안 패치가 제안되더라도 곧바로 --force를 적용하지 않았다. breaking change가 필요한 항목과 lockfile을 대량 재작성하는 변경은 환경 이전과 분리해 별도 업그레이드 작업으로 다루는 편이 안전하다.
개발 서버보다 전체 검증이 먼저다
페이지 하나가 브라우저에서 보인다고 이전이 끝난 것은 아니다. 다음 검사를 순서대로 실행했다.
npm run audit:posts
npm run lint
npm run typecheck
npm run build
npm audit --omit=devproduction build는 정적 페이지 생성, MDX 파싱, 타입 검사, 이미지 처리 경로를 한 번에 확인한다. 이번 프로젝트에서는 128개의 정적 페이지가 생성되면서 이전 환경과 동일한 결과를 확인했다.
샌드박스 환경에서는 Turbopack이 내부 프로세스를 위해 포트를 바인딩하는 단계에서 실패할 수 있다. 오류 메시지에 binding to a port와 권한 거부가 함께 나타난다면 코드 문제로 단정하지 말고, 동일 빌드를 정상 권한의 로컬 환경에서 다시 실행해 구분해야 한다.
운영체제 경로는 환경변수와 상대경로로 바꾼다
일부 보조 스크립트에는 Windows 절대 경로가 남아 있었다. 특정 디스크 이름을 macOS 볼륨 이름으로 교체하면 다른 컴퓨터에서 다시 깨진다. 사용자가 지정한 환경변수를 우선하고, 기본값은 프로젝트의 형제 디렉터리를 탐색하도록 바꿨다.
const sourceRoot = path.resolve(
process.env.EXTERNAL_PROJECT_ROOT ??
path.join(projectRoot, "..", "ExternalProject"),
);외부 프로젝트가 없을 때는 블로그 자체의 빌드를 막지 않고 해당 동기화 기능만 사용할 수 없는 상태로 남기는 것이 핵심이다. 기술 문서 속 Windows 실습 예제까지 일괄 변경할 필요는 없다.
이전 작업에서 얻은 기준
운영체제 이전은 파일 복사보다 무결성 검증에 가깝다. 이번 작업에서 유효했던 기준은 다음과 같다.
- 원격 Git은 추적 파일의 기준점으로 사용하되 로컬 비공개 파일의 백업으로 간주하지 않는다.
- 합치기 전에는 현재 추적 파일을 별도 위치에 보존한다.
- 삭제 명령 없이 기준본을 겹쳐 놓고 Git 상태로 결과를 확인한다.
- 플랫폼별 의존성은 lockfile과
npm ci로 다시 설치한다. - 개발 서버 실행보다 콘텐츠 감사와 production build를 완료 조건으로 둔다.
- 보안 업그레이드와 환경 이전을 한 번의 대규모 lockfile 변경으로 섞지 않는다.
이 과정을 거치면 “내 컴퓨터에서는 실행된다”보다 더 강한 상태를 만들 수 있다. Git 기록, 로컬 전용 자산, CI 버전, 네이티브 패키지, 전체 빌드가 모두 설명 가능한 상태가 되어야 개발환경 이전이 끝났다고 판단할 수 있다.
관련 글
Cloud & Platform Engineering
Azure CLI/PowerShell과 SQL Server 운영 자동화 흐름
Azure CLI와 PowerShell로 VM, 네트워크, NSG를 반복 가능하게 구성하고 SQL Server 배포와 Azure SQL 마이그레이션을 운영 관점으로 정리합니다.
Cloud & Platform Engineering
S3, CloudFront, Terraform으로 정적 호스팅 구성하기
S3 정적 오리진과 CloudFront 배포를 Terraform으로 선언하고 GitHub Actions 배포 흐름까지 연결합니다.
Cloud & Platform Engineering
클라우드 네트워크 주소 설계와 라우팅 기초
2진수, CIDR, 서브넷 마스크, 게이트웨이, VNet, Load Balancer 개념을 클라우드 네트워크 설계 흐름으로 연결해 정리합니다.