← 블로그 목록

AI가 만든 서비스인데 배포 후 안 되는 이유 TOP 10

AI로 만든 서비스가 로컬이나 미리보기에서는 잘 되다가 Vercel, Netlify 같은 실제 배포 환경에서 깨지는 대표 원인 10가지를 정리했습니다.

AI로 만든 서비스는 시작이 빠릅니다. Cursor, Lovable, Bolt 같은 도구로 화면을 만들고, 로그인과 데이터 저장까지 붙이면 꽤 그럴듯한 제품처럼 보입니다.

그런데 실제 배포를 해보면 이야기가 달라집니다.

미리보기에서는 됐는데 운영 주소에서는 안 됩니다. 로컬에서는 로그인되는데 배포하면 콜백 오류가 납니다. 페이지는 뜨는데 API 호출만 실패합니다. 어제까지 되던 기능이 도메인을 연결한 뒤부터 깨집니다.

이건 이상한 일이 아닙니다. AI가 코드를 만들 수는 있지만, 운영 환경의 계정 설정, 도메인, 환경 변수, 보안 정책까지 자동으로 맞춰주지는 못합니다. 배포 후 문제가 생긴다면 아래 10가지를 먼저 확인해보세요.

1. 배포 환경에 환경 변수가 없다

가장 흔한 원인입니다.

로컬에서는 .env.local에 Supabase URL, API key, OAuth client id 같은 값이 들어 있습니다. 하지만 Vercel이나 Netlify에 배포하면 그 파일을 그대로 읽지 않습니다. 배포 서비스의 Environment Variables에 따로 등록해야 합니다.

증상은 보통 이렇게 나옵니다.

  • process.env가 undefined로 나온다
  • Supabase나 Firebase 연결이 실패한다
  • API 호출 주소가 비어 있다
  • 로컬에서는 되는데 운영에서만 흰 화면이 뜬다

환경 변수를 추가했다면 저장만 하고 끝내면 안 됩니다. 새 값이 들어간 상태로 다시 배포해야 합니다.

2. NEXT_PUBLIC_을 잘못 붙였거나 빠뜨렸다

Next.js를 쓰는 프로젝트에서 자주 나옵니다.

브라우저에서 읽어야 하는 환경 변수는 이름 앞에 NEXT_PUBLIC_이 붙어야 합니다. 예를 들어 클라이언트 화면에서 Supabase anon key를 쓴다면 NEXT_PUBLIC_SUPABASE_ANON_KEY처럼 되어 있어야 합니다.

반대로 서버에서만 써야 하는 secret key나 service role key에 NEXT_PUBLIC_을 붙이면 위험합니다. 브라우저에 노출될 수 있기 때문입니다.

정리하면 간단합니다.

  • 화면에서 써야 하는 공개 값: NEXT_PUBLIC_ 필요
  • 서버에서만 써야 하는 비밀 값: NEXT_PUBLIC_ 금지

AI가 처음 만든 코드에서는 이 경계가 흐릿하게 섞여 있는 경우가 많습니다.

3. OAuth Redirect URI에 운영 도메인이 없다

로그인 관련 배포 오류는 거의 여기서 시작합니다.

카카오, 네이버, 구글, Clerk, Supabase Auth 같은 로그인 서비스는 허용된 콜백 주소로만 사용자를 돌려보냅니다. 개발 중에는 localhost 주소만 등록해두고, 배포 후 운영 도메인을 빼먹는 일이 정말 많습니다.

예를 들어 로컬 콜백은 이런 식입니다.

http://localhost:3000/auth/callback

하지만 배포 후에는 이런 운영 주소도 등록되어 있어야 합니다.

https://my-service.com/auth/callback

www 차이, http와 https 차이, 마지막 슬래시 차이도 문제가 될 수 있습니다. OAuth는 대충 비슷한 주소를 허용하지 않습니다. 글자 단위로 맞아야 합니다.

4. 코드 안에 localhost가 남아 있다

배포했는데도 API 요청이 localhost로 가는 경우가 있습니다.

AI가 개발 중에 임시로 넣어둔 주소가 그대로 남았거나, BASE_URL 환경 변수가 로컬 주소로 고정되어 있는 경우입니다. 실제 사용자 브라우저에서 localhost는 사용자의 컴퓨터를 뜻합니다. 당연히 내 개발 서버로 연결되지 않습니다.

검색해볼 키워드는 단순합니다.

  • localhost
  • 127.0.0.1
  • .vercel.app 미리보기 주소
  • 예전 테스트 도메인
  • 임시 API 주소

운영 배포에서는 프론트 주소, API 주소, 콜백 주소가 모두 운영 기준으로 맞아야 합니다.

5. 빌드 명령이나 패키지 설정이 맞지 않는다

미리보기에서는 되지만 실제 배포 빌드에서 실패하는 경우입니다.

AI 빌더 안의 미리보기는 개발 서버에 가깝습니다. 반면 Vercel 배포는 의존성을 설치하고, 빌드 명령을 실행하고, 결과물을 정적 파일이나 서버 함수로 만들어냅니다.

여기서 다음 문제가 자주 나옵니다.

  • package.json의 build 명령이 없다
  • 필요한 패키지가 dependencies가 아니라 devDependencies에 잘못 들어 있다
  • lockfile이 꼬여서 배포 서버에서 다른 버전이 설치된다
  • Node.js 버전이 로컬과 배포에서 다르다
  • TypeScript나 ESLint 에러가 빌드에서만 드러난다

배포가 실패했다면 AI에게 코드부터 고치게 하기 전에, 빌드 로그의 첫 번째 의미 있는 에러를 먼저 봐야 합니다.

6. 파일명 대소문자가 배포 서버에서만 터진다

맥에서는 멀쩡한데 Vercel에서만 Module not found가 나는 경우가 있습니다.

macOS는 기본 설정에서 파일명 대소문자를 느슨하게 처리하는 경우가 많습니다. 하지만 배포 서버는 보통 Linux라서 대소문자를 정확히 구분합니다.

예를 들어 실제 파일은 components/Header.tsx인데 코드에서 components/header로 import했다면, 내 컴퓨터에서는 넘어갈 수 있지만 배포 서버에서는 실패합니다.

이 문제는 AI가 파일을 만들고 옮기는 과정에서 종종 생깁니다. 비슷한 이름의 파일이 여러 개 생겼다면 더 의심해봐야 합니다.

7. 정적 배포와 서버 기능이 충돌한다

AI가 만든 프로젝트에서 은근히 자주 나오는 문제입니다.

랜딩페이지처럼 정적으로 배포해야 하는 프로젝트에 API route, 서버 액션, 동적 쿠키 처리, 파일 업로드 같은 서버 기능이 섞이면 배포 방식과 맞지 않을 수 있습니다.

예를 들어 Next.js에서 output: export를 쓰면 정적 HTML을 내보내는 방식입니다. 이 구조에서는 서버에서 매번 실행되어야 하는 API route나 서버 액션을 그대로 쓸 수 없습니다.

증상은 다양합니다.

  • 빌드는 되는데 특정 기능만 404가 난다
  • 폼 제출이 배포 후 동작하지 않는다
  • 로컬에서는 API route가 되는데 정적 export 후에는 사라진다
  • 인증이나 결제 콜백이 돌아올 곳이 없다

배포 방식을 먼저 정하고, 그 방식 안에서 가능한 기능만 넣어야 합니다.

8. 브라우저 전용 코드가 서버에서 실행된다

Next.js App Router를 쓰면 서버에서 먼저 화면을 만들고, 브라우저에서 다시 이어받습니다. 이때 window, document, localStorage 같은 브라우저 전용 값을 서버 렌더링 중에 쓰면 문제가 납니다.

대표 증상은 두 가지입니다.

  • window is not defined
  • Hydration failed because the initial UI does not match what was rendered on the server

Date.now, Math.random, new Date처럼 매번 값이 달라지는 코드도 hydration mismatch를 만들 수 있습니다.

브라우저에서만 필요한 값은 useEffect 안에서 읽거나, 클라이언트 컴포넌트로 분리하는 편이 안전합니다. AI는 화면이 보이게 만드는 데 집중하다가 이 경계를 놓치는 경우가 많습니다.

9. CORS와 쿠키 설정이 운영 도메인 기준이 아니다

API는 살아 있는데 브라우저에서만 막히는 경우입니다.

프론트엔드와 API 서버의 도메인이 다르면 브라우저는 CORS 규칙을 적용합니다. API 서버가 운영 프론트 도메인을 허용하지 않으면 요청은 차단됩니다.

쿠키 인증을 쓰는 경우에는 더 까다롭습니다.

  • fetch 요청에 credentials 설정이 빠져 있다
  • 서버가 credentials를 허용하지 않는다
  • Access-Control-Allow-Origin이 *로 되어 있다
  • SameSite, Secure, domain 설정이 운영 HTTPS 환경과 맞지 않는다

특히 "로그인은 된 것 같은데 새로고침하면 풀린다"면 쿠키와 세션 설정을 먼저 보세요.

10. 외부 서비스의 운영 설정이 빠져 있다

AI가 만든 서비스는 보통 외부 서비스에 많이 기대고 있습니다. Supabase, Firebase, Stripe, 토스페이먼츠, Resend, Clerk, OAuth 제공자 같은 것들입니다.

코드는 만들어졌지만 각 서비스의 운영 설정이 빠지면 배포 후 기능이 멈춥니다.

자주 빠지는 설정은 이렇습니다.

  • Supabase RLS 정책
  • Firebase Authorized domains
  • OAuth callback URL
  • 결제 성공 URL과 실패 URL
  • 이메일 발송 도메인 인증
  • Storage bucket 공개 권한
  • 운영용 API key와 테스트용 API key 구분

이 문제는 코드만 봐서는 잘 안 풀립니다. 외부 서비스 대시보드와 배포 환경을 같이 확인해야 합니다.

먼저 확인할 순서

배포 후 서비스가 안 된다면 아래 순서로 보면 됩니다.

  1. 배포 로그에서 첫 번째 에러를 확인한다
  2. 환경 변수가 배포 서비스에 들어 있는지 본다
  3. 운영 도메인이 OAuth와 외부 서비스에 등록되어 있는지 확인한다
  4. 코드에 localhost나 예전 미리보기 주소가 남아 있는지 검색한다
  5. API 요청이 막히면 CORS, 쿠키, 인증 헤더를 확인한다
  6. 데이터가 안 보이면 Supabase RLS나 Firebase 권한을 확인한다
  7. 로컬에서 npm run build를 직접 실행해본다

이 순서대로 보면 "코드 문제인지", "설정 문제인지", "외부 서비스 권한 문제인지"가 조금씩 갈립니다.

그래도 안 풀린다면

배포 후 오류는 AI가 특히 어려워하는 영역입니다. 코드만 보면 답이 안 나오고, 배포 서비스, 도메인, 인증 콘솔, 데이터베이스 권한까지 같이 봐야 하기 때문입니다.

문의할 때는 아래 정보만 정리해도 진단이 훨씬 빨라집니다.

  • 서비스 주소
  • 사용한 AI 도구: Cursor, Lovable, Bolt 등
  • 배포 서비스: Vercel, Netlify, Cloudflare 등
  • 에러 메시지나 배포 로그
  • 문제가 생기는 화면과 재현 순서
  • 연결된 외부 서비스: Supabase, Firebase, 결제, OAuth 등

비밀번호나 API 키를 처음부터 보낼 필요는 없습니다. 키 값은 가리고, 어떤 이름의 환경 변수가 있는지만 알려줘도 시작할 수 있습니다.

LastFix는 AI로 만든 서비스가 배포 후 막혔을 때, 무작정 다시 만들기보다 원인부터 좁혀봅니다. 배포 환경, 코드 구조, 외부 서비스 설정을 함께 보고 지금 당장 고쳐야 할 부분부터 정리합니다.

관련 글: 바이브코더가 가장 자주 만나는 버그 TOP 3, Vercel 환경변수가 적용 안 될 때, 비개발자가 점검할 5가지, 비개발자의 바이브코딩, 왜 배포에서 자주 막힐까?

AI·바이브코딩으로 해결되지 않는 개발 이슈, 먼저 원인부터 확인하세요

Cursor 에러, Vercel·Next.js 배포 실패, 결제·예약 연동 오류, 소규모 기능 개발을 단건 중심으로 진단합니다. 월 구독 파트너는 정식 상품을 준비 중입니다.