47장. 인터넷에 서비스 배포하기
배포를 해야 비로소 서비스가 된다
로컬 컴퓨터에서만 열리는 앱은 아직 프로젝트에 가깝습니다. 내가 만든 기능이 잘 보이고, 버튼도 눌리고, 데이터도 저장되면 뿌듯하죠. 하지만 그 주소가 내 컴퓨터 안에만 머물러 있다면, 다른 사람은 그 결과를 볼 수 없습니다. 서비스는 결국 다른 사람이 접속할 수 있어야 서비스입니다.
그래서 배포는 단순히 마지막 버튼을 누르는 일이 아닙니다. "이제 이걸 세상에 공개해도 된다"라고 선언하는 순간에 가깝습니다. Next.js를 실제 운영 환경으로 올리는 가장 쉬운 길로는 보통 Vercel이 먼저 추천됩니다.1 특히 Next.js는 Vercel에서 별도 복잡한 설정 없이 배포할 수 있도록 맞물려 설계되어 있어서, 초보자에게도 시작 장벽이 낮습니다.2
이번 장의 목표는 어렵지 않습니다. 우리가 만든 풀스택 웹 서비스를 Vercel에 올리고, 인터넷 주소를 받아서, 직접 접속해 보는 것. 그 한 번의 경험이 굉장히 큽니다. 이 순간부터 여러분은 "공부용으로 만든 화면"이 아니라, 실제로 접속 가능한 웹 서비스를 손에 넣게 됩니다.
배포 전에 딱 한 번만 점검하자
배포는 마법이 아닙니다. 로컬에서 불안정한 앱이 인터넷에 올라간다고 갑자기 멀쩡해지지는 않습니다. 오히려 배포는 숨겨져 있던 문제를 더 정직하게 드러냅니다. 그래서 배포 버튼을 누르기 전에 아래 다섯 가지를 한 번만 확인하면 훨씬 덜 막힙니다.
로컬에서
npm run build가 성공하는가GitHub에 최신 코드가 올라가 있는가
Vercel에 넣어야 할 환경변수가 정리되어 있는가
로그인 기능이 있다면 인증 서비스의 허용 주소를 나중에 추가할 준비가 되어 있는가
테스트용 데이터와 운영용 데이터를 헷갈리지 않을 준비가 되어 있는가
여기서 가장 중요한 것은 첫 번째입니다. 개발 서버가 뜨는 것과 배포 빌드가 성공하는 것은 다릅니다. npm run dev에서는 괜찮았는데 npm run build에서 깨지는 경우가 생각보다 많습니다. 예를 들어 타입 오류, 잘못된 import, 서버 전용 코드와 클라이언트 코드를 섞어 쓴 문제는 이 단계에서 자주 드러납니다.
또 하나. 환경변수 자체는 지난 장에서 자세히 다뤘으니 여기서는 짧게만 기억하면 됩니다. 로컬의 .env.local이 있다고 해서 Vercel이 그 값을 자동으로 아는 것은 아닙니다. 배포 환경에는 배포 환경의 변수를 따로 넣어야 합니다.
가장 쉬운 방식은 GitHub와 Vercel을 연결하는 것이다
처음 배포할 때는 Vercel 대시보드에서 GitHub 저장소를 연결하는 방식이 가장 쉽습니다. 이 방식을 쓰면 Vercel이 저장소를 보고 자동으로 빌드하고, Next.js 프로젝트도 알아서 감지해 줍니다.2 한 번 연결해 두면 그다음부터는 브랜치에 푸시할 때마다 새 배포가 만들어집니다.3
이 흐름을 초보자 눈높이로 아주 단순하게 줄이면 이렇습니다.
코드를 GitHub에 올린다. Vercel이 그 코드를 가져간다. 빌드한다. 성공하면 인터넷 주소를 준다.
이때 꽤 재미있는 점이 있습니다. Vercel은 배포할 때마다 고유한 URL을 만들어 줍니다.4 그래서 "지금 막 올린 이 버전"을 따로 확인할 수 있습니다. 잘되면 기쁘고, 안 되면 로그를 보며 바로 원인을 찾을 수 있죠.4
첫 배포, 순서대로 해보자
GitHub에 최신 코드를 올린다
먼저 프로젝트가 GitHub 저장소에 올라가 있어야 합니다. 이미 앞 장들에서 Git과 GitHub를 익혔으니, 여기서는 최신 상태인지 확인하는 것이 핵심입니다. 특히 main 브랜치가 기준이 될 가능성이 높으니, 지금 배포하고 싶은 코드가 정말 그 브랜치에 있는지 보세요.
이 단계에서 추천하는 습관이 하나 있습니다. 배포 직전 커밋 메시지를 애매하게 쓰지 않는 것입니다. fix, update보다 deploy: first production-ready version처럼 남겨 두면 나중에 Vercel 대시보드에서 어떤 배포가 어떤 변경과 연결되는지 알아보기 쉽습니다.
Vercel에서 새 프로젝트를 만든다
이제 Vercel에 로그인합니다. 보통은 GitHub 계정으로 로그인하는 것이 가장 편합니다. 로그인 후 New Project 또는 Add New Project를 누르면, 연결 가능한 저장소 목록이 보입니다.
여기서 배포할 저장소를 선택하면 됩니다. 저장소를 가져오는 과정을 보통 import라고 부르는데, 겁먹을 필요는 없습니다. "코드를 복사해 와서 배포 대상으로 등록한다" 정도로 이해하면 충분합니다.
설정 화면에서 확인할 것들
저장소를 선택하면 설정 화면이 나옵니다. 초보자는 여기서 괜히 긴장합니다. 뭔가 잘못 누르면 서버실이 폭발할 것 같거든요. 다행히 대부분은 기본값으로 충분합니다.
먼저 프로젝트 이름을 확인합니다. 이 이름은 기본적으로 프로젝트이름.vercel.app 주소에 반영될 수 있어서, 너무 난해하지 않게 두는 편이 좋습니다.
그다음 Framework Preset이 Next.js로 잘 잡히는지 봅니다. 보통 자동 감지됩니다.2 자동으로 잡혔다면 일단 좋은 출발입니다.
그리고 아주 중요한 항목이 하나 있습니다. Environment Variables입니다. 여기에 지난 장에서 정리한 값들을 넣어야 합니다. 예를 들어 Supabase URL, anon key, 서버 전용 비밀 키, 앱 URL 같은 값들입니다. 이때 공개용과 비공개용을 헷갈리지 않는 것이 중요합니다.
마지막으로 프로젝트가 모노레포가 아니라면 Root Directory는 보통 비워 두거나 기본값 그대로 둡니다. 하지만 저장소 안에 앱이 여러 개 있다면 이야기가 달라집니다. 이 부분은 뒤에서 짧게 다시 설명하겠습니다.
Deploy 버튼을 누른다
이제 드디어 배포 버튼을 누릅니다.
그러면 Vercel이 의존성을 설치하고, 빌드하고, 결과를 배포합니다. 이 과정에서 성공하면 배포 URL이 생깁니다.4 실패하면 겁먹지 말고 빌드 로그를 보면 됩니다. Vercel은 배포 상세 화면에서 빌드 상태, 함수 정보, 로그 같은 배포 관련 정보를 확인할 수 있게 해 줍니다.4
초보자에게 이 순간은 꽤 묘합니다. 몇 분 전까지 내 노트북에서만 열리던 서비스가 갑자기 인터넷 주소를 갖게 되니까요. 마치 방 안에서만 연습하던 밴드가 처음 공연장 마이크를 잡는 느낌입니다. 음, 약간 떨리지만 꽤 신납니다.
배포 URL로 직접 들어가 본다
배포가 끝나면 https://무언가.vercel.app 형태의 주소가 생깁니다. 이제 그 주소를 직접 열어 보세요. 여기서 중요한 건 "메인 화면이 뜨는가"만 보는 것이 아닙니다. 실제 사용자처럼 한 바퀴 돌아봐야 합니다.
회원가입과 로그인, 글 작성, 수정, 삭제, 목록과 상세 이동, 검색까지 직접 눌러 보세요. 서비스는 첫 화면보다 전체 흐름이 더 중요합니다. 홈페이지는 멀쩡한데 로그인 후 글 저장에서 터지는 경우가 아주 흔합니다.
배포가 끝나면 그다음부터는 훨씬 편해진다
GitHub 저장소를 Vercel에 연결해 두면, 이후에는 브랜치 기반 배포 흐름을 자연스럽게 사용할 수 있습니다. 보통 생산 브랜치인 main에 반영된 최신 코드는 프로덕션 배포로 이어지고, 그 외 브랜치의 변경은 미리보기 배포로 확인할 수 있습니다.3 즉, 여러분은 이제 이런 흐름으로 일할 수 있습니다.
기능을 만든다. 브랜치에 푸시한다. 미리보기 주소를 확인한다. 괜찮으면 main에 합친다. 실제 서비스가 갱신된다.
이게 왜 좋을까요. 예전에는 "수정하면 바로 실서비스가 망가질까 봐" 겁났다면, 이제는 먼저 미리보기 주소에서 확인하고 나서 배포할 수 있기 때문입니다. 작은 안전장치 하나가 작업 자신감을 꽤 올려 줍니다.
초보자가 가장 자주 만나는 배포 문제
빌드는 되는데 페이지가 이상하게 보인다
이 경우는 대개 환경변수 값이 빠졌거나, 배포 환경에서만 달라지는 설정 때문입니다. 예를 들어 로컬에서는 http://localhost:3000을 기준으로 동작하던 코드가 배포 후에는 실제 도메인을 써야 하는데 그대로 남아 있으면 링크나 리다이렉트가 꼬일 수 있습니다.
특히 로그인 기능은 주의가 필요합니다. 인증 서비스는 보통 "어느 주소에서 돌아왔을 때 로그인 성공으로 인정할지"를 등록해 둡니다. 그래서 로컬 주소만 등록되어 있으면, 배포 후 로그인은 실패하거나 엉뚱한 페이지로 튈 수 있습니다. 배포 URL을 허용 주소에 추가해야 합니다.
로컬에서는 되는데 Vercel에서 빌드가 실패한다
이때는 가장 먼저 로컬에서 npm run build를 다시 실행해 보세요. 개발 서버는 느슨하게 넘어가지만, 실제 배포 빌드는 더 엄격합니다. TypeScript 오류, import 경로 문제, 서버 전용 모듈의 잘못된 사용이 자주 걸립니다.
그리고 Vercel의 빌드 로그를 꼭 보세요. 배포는 실패해도 흔적을 남깁니다. 그 흔적이 바로 로그입니다.4 초보자일수록 "안 되네?" 하고 감으로 고치기보다, 로그에 나온 첫 번째 오류 메시지를 중심으로 원인을 찾는 습관이 중요합니다.
메인 화면은 뜨는데 API가 실패한다
이 경우는 백엔드 함수나 데이터베이스 연결 쪽 문제일 가능성이 큽니다. 프론트엔드는 정적 화면이라 잘 떠도, 서버 함수는 환경변수나 권한 설정이 맞아야 작동합니다. 데이터베이스 URL, 서비스 키, 외부 API 키가 누락되어 있지 않은지 확인하세요.
또 하나 자주 보이는 실수는 "클라이언트에서 서버 전용 키를 읽으려 한 경우"입니다. 이런 실수는 로컬에서 얼핏 숨어 있다가 배포 후 더 분명하게 드러납니다.
이미지나 외부 리소스가 안 보인다
Next.js에서 외부 이미지를 쓴다면 허용 도메인 설정이 필요할 수 있습니다. 로컬에서는 몰랐는데 배포 후 이미지만 깨지는 이유가 여기에 있는 경우가 많습니다. 화면 전체가 망가진 게 아니라 리소스 설정 하나가 빠진 것이니, 침착하게 설정 파일과 에러 메시지를 같이 보면 됩니다.
프로젝트가 여러 앱이라면 Root Directory를 꼭 본다
지금 책의 실습은 보통 하나의 Next.js 앱을 기준으로 진행하지만, 나중에는 apps/web, apps/admin처럼 앱이 둘 이상인 구조를 쓰게 될 수도 있습니다. 이럴 때 초보자가 가장 헷갈리는 부분이 바로 "Vercel 프로젝트도 하나면 되지 않나?"라는 질문입니다.
만약 web과 admin이 각각 독립적인 Next.js 앱이라면, 보통은 같은 GitHub 저장소를 두 번 가져오되 Root Directory를 다르게 잡아 각각 별도 프로젝트로 배포하는 편이 자연스럽습니다.5 즉, GitHub 저장소는 하나여도 Vercel 프로젝트는 둘일 수 있습니다.5
이 부분은 폴더가 두 개라고 해서 /admin 하위 경로로 자동 연결되는 구조가 아닙니다. "독립 실행되는 앱이 둘이다"라고 이해하는 편이 맞습니다. 나중에 관리자 페이지를 따로 운영하게 되면 이 개념이 꽤 유용합니다.
더 꼼꼼하게 가고 싶다면 GitHub Actions도 있다
입문 단계에서는 GitHub 저장소를 Vercel에 직접 연결하는 방식이 가장 쉽습니다. 하지만 팀이 커지거나, 배포 전에 린트와 테스트를 꼭 통과시키고 싶거나, 빌드를 GitHub에서 직접 관리하고 싶다면 GitHub Actions를 붙일 수도 있습니다.
이 방식에서는 보통 Vercel CLI로 환경변수를 가져오고, GitHub Actions 안에서 빌드한 뒤, 빌드 결과물만 Vercel에 올립니다. Vercel 예제도 vercel pull, vercel build, vercel deploy --prebuilt 흐름을 안내합니다.6
다만 지금 단계에서는 꼭 이 길로 갈 필요는 없습니다. 처음 서비스 하나를 세상에 공개하는 데 필요한 것은 복잡한 자동화보다 성공하는 첫 배포 경험입니다. 자동화는 두 번째 감동으로 남겨 둬도 충분합니다.
배포 직후에는 이것만 꼭 확인하자
배포가 끝났다고 바로 끝난 것은 아닙니다. 막 구운 빵도 한 번 잘라 봐야 속이 익었는지 알 수 있듯, 서비스도 공개 직후 점검이 필요합니다.
첫 화면이 정상적으로 열린다
회원가입과 로그인이 실제로 동작한다
글 작성, 수정, 삭제가 모두 된다
목록과 상세 화면 이동이 자연스럽다
검색 기능이 비어 있는 상태와 결과가 있는 상태 모두 잘 보인다
모바일 화면에서도 크게 깨지지 않는다
브라우저 새로고침을 해도 이상한 페이지로 가지 않는다
이 체크는 대단한 QA 문서가 아닙니다. 하지만 초보자에게는 가장 실용적인 첫 운영 점검표입니다.
배포는 기술이면서 동시에 심리적인 문턱이다
처음 배포할 때 많은 사람이 이상하게 긴장합니다. 코드가 틀릴까 봐서만은 아닙니다. "이제 진짜로 공개되는구나"라는 감각 때문입니다. 내 실수가 URL이 되어 세상에 노출된다는 사실이 조금 무섭게 느껴지죠.
그런데 바로 그 경험이 중요합니다. 배포를 해보면 개발이 더 이상 추상적인 공부가 아닙니다. 브라우저 탭 하나, 주소창 하나, 로그인 하나, 글쓰기 하나가 모두 현실의 동작으로 바뀝니다. 이 감각이 생기면 이후에 배우는 배포 자동화, 도메인 연결, 로그 분석, 운영 비용 같은 주제도 훨씬 실제적으로 다가옵니다.
그러니 이번 장의 핵심은 단순합니다. 일단 올려보는 것. 완벽한 서비스를 올리는 것이 아니라, 실제로 접속 가능한 첫 서비스를 올리는 것이 중요합니다.
이번 장 정리
이번 장에서는 Vercel을 중심으로 서비스를 인터넷에 배포하는 흐름을 살펴봤습니다.
배포 전에 로컬 빌드와 환경설정을 점검하고, GitHub 저장소를 Vercel에 연결하고, 자동 감지된 Next.js 설정을 확인한 뒤, 실제 배포 URL에서 전체 사용자 흐름을 검증하는 것이 핵심이었습니다. 그리고 한 번 연결해 두면 이후에는 브랜치별 미리보기 배포와 프로덕션 배포 흐름을 자연스럽게 이어 갈 수 있습니다.3
이제 여러분의 앱은 더 이상 내 컴퓨터 속 프로젝트가 아닙니다. 누군가에게 주소를 보낼 수 있는 서비스입니다. 아주 작은 차이처럼 보이지만, 실제로는 엄청 큰 변화입니다.
참고
1Deploy to Vercel | Next.js Docs
3Deploying Git Repositories with Vercel
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.