AI가 구축했거나(또는 수동으로 구축한) Next.js 앱이 next build 과정에서 Error: supabaseUrl is required. 오류로 인해 중단되는 경우, 일반적인 원인은 한 줄에 있습니다. 바로 라우트 파일의 최상위 레벨에서 생성된 Supabase 클라이언트가 환경 변수(env vars)가 설정되지 않은 빌드 시점에 평가되면서 발생합니다.
저희는 작은 합성 앱으로 이를 재현했고, 가장 작은 수정 사항을 적용하여 빌드가 실패에서 성공으로 전환되는 것을 확인했습니다. 아래에 정확한 오류 내용, 원인, 해결 방법, 검증 방법, 그리고 저희가 테스트하지 않은 내용을 정리했습니다.
정확한 오류 (The exact error)
저희의 재현 과정(npx next build, .env 파일 없음, Supabase 변수 설정 안 함)에서 발생한 오류는 다음과 같습니다:
Collecting page data using 5 workers ...
Error: Failed to collect configuration for /api/waitlist
at ignore-listed frames {
...
종료 코드(Exit code)가 1입니다. 동일한 내용은 vercel/next.js#69095와 같은 공개 보고서에서도 나타납니다 (Vercel 빌드, Next 14.2.3).
사용한 버전 (Versions we used)
원인 (Cause)
next build 과정에서 Next.js는 페이지 데이터를 수집하기 위해 라우트 모듈들을 로드합니다. 만약 라우트 파일이 아래와 같이 **모듈 스코프(module scope)**에서 코드를 실행한다면:
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
...
...이 경우 createClient가 빌드 과정 중에 실행됩니다. 만약 해당 변수가 빌드 환경(.env.local에 없거나, 호스트에 설정되지 않았거나, 오타가 있거나, 프리뷰를 빌드하는 동안 프로덕션에만 스코프된 경우)에서 누락되면, createClient가 오류를 발생시키고 전체 빌드가 실패합니다. AI 코딩 도구들은 이러한 최상위 레벨 패턴을 많이 생성하는 경향이 있습니다.
가장 작은 작동 수정 (Smallest working fix)
클라이언트를 함수 내부에서 생성하고 핸들러(handler) 내에서 호출하세요.
수정 전 (실패):
import { createClient } from "@supabase/supabase-js";
const supabase = createClient(
...
수정 후 (빌드 성공):
import { createClient } from "@supabase/supabase-js";
function getSupabase() {
...
AI 코딩 도구를 사용한다면, 다음과 같은 프롬프트가 변경 사항을 설명합니다(이 프롬프트를 어떤 도구에서도 테스트하지 않았으므로, diff를 직접 검토해 주세요):
My Next.js build fails with "Error: supabaseUrl is required." Find every file that calls createClient from @supabase/supabase-js at the top level of a module. Move each call into a getSupabase() function that reads process.env at request time and throws a clear error naming the missing variable. Don't rename variables, don't print key values, don't change anything else. Show me the diff.
검증 방법
2026-10-18에 실행된 모든 테스트는 .env 파일이 없고 Supabase 변수가 설정되지 않은 상태였습니다:
- 변경 전:
npx next build → 위 오류로 실패, 종료 코드 1.
- 변경 후:
npx next build → 종료 코드 0; 출력에서 ƒ /api/waitlist가 동적 라우트로 나열됨.
- 변경 후, 키 누락 시 런타임 테스트:
npx next start를 실행한 다음 가짜 이메일로 POST /api/waitlist 요청 → HTTP/1.1 500 및 {"ok":false,"error":"Missing NEXT_PUBLIC_SUPABASE_URL or NEXT_PUBLIC_SUPABASE_ANON_KEY"}.
이 수정 사항이 하지 않는 것: 키를 제공하는 것이 아닙니다. 빌드를 통과시키고 실패 지점을 명확한 요청 시간 오류로 옮기는 것입니다. 배포된 앱이 Supabase가 필요하다면, 여전히 호스트에서 변수를 설정해야 합니다. NEXT_PUBLIC_ 값은 빌드 시간에 인라인(inlined)되므로, 변경 후에는 재배포해야 합니다 (Next.js의 문서화된 동작이며, 여기서는 다시 테스트하지 않았습니다).
검증되지 않은 사항
한계점에 대해 솔직하게 말씀드리자면:
- 실제 Supabase 프로젝트 없음: 성공적인 삽입(insert)이나 Supabase로의 네트워크 호출을 한 적이 없습니다.
- Vercel, Netlify 또는 기타 호스팅 빌드 환경 아님.
- Lovable, Bolt, Cursor 또는 v0 출력물 없음. 저희 앱은 공용 보고서의 패턴을 모델링한 수작업(hand-written) 및 합성(synthetic)입니다.
- 다른 버전(Next 14 포함), Pages Router, 또는 Vite/React 앱 아님.
- 위 AI 프롬프트는 어떤 도구에서도 실행되지 않았습니다.
- "CI의 플레이스홀더 환경 변수" 임시 해결책은 테스트되지 않았습니다.
- 동일한 증상을 보이는 다른 원인(오타가 있거나 접두사가 붙지 않은 변수 이름, 누락된
.env.local 등)은 재현하지 못했습니다.
빠른 문제 해결 (Quick troubleshooting)
- 빌드는 성공하지만 라이브 앱에서 "Missing NEXT_PUBLIC_SUPABASE_URL…" 반환: 해당 변수를 정확한 이름으로 호스팅 환경에 설정한 후 다시 배포하세요.
- 수정 후에도 동일한 빌드 오류 발생: 다른 파일이 여전히 최상위 레벨에서 클라이언트를 생성하고 있습니다.
createClient(를 검색해 보세요.
- 로컬에서는 작동하지만 호스트에서 실패:
.env.local은 일반적으로 커밋되지 않으므로, 호스팅 환경에서는 이를 볼 수 없습니다.
보안: 서비스 역할 키(service-role key)는 브라우저의 모든 곳으로 전송되므로 NEXT_PUBLIC_ 변수에 절대 넣지 마세요. 그리고 실제 키를 AI 채팅이나 이슈에 붙여넣지 마세요.
원래 가이드와 이전/이후 파일은 The Agent Ledger에서 확인할 수 있습니다: supabaseUrl is required: next build fix.
AI 공개: 이 글은 AI의 도움을 받아 작성되었습니다. 위에서 설명한 재현 및 이전/이후 빌드 실행은 게시 전에 실제로 수행되고 로그를 통해 확인되었습니다.