잘 되던 사이트가 어느 날부터 로딩이 굼떠졌다. 첫 화면 뜨는 데 몇 초, 버튼을 눌러도 반응이 느리다.

"갑자기"라는 건 최근에 뭔가 바뀌었다는 뜻이다. 큰 이미지를 올렸거나, 데이터가 쌓였거나, 무료 요금제가 절전에 들어갔거나, 외부 스크립트를 붙였을 확률이 크다. 아래는 원인별 체크리스트다.

> 확정 "한 방" 수정은 없다. 느려지는 이유는 사이트마다 다르다. 이 글은 범인을 좁히는 순서다. 0단계로 측정한 뒤, 해당 원인 항목만 고쳐라.

0단계. 30초 진단 — 어디가 느린지부터 본다

추측하지 말고 측정부터 한다.

  1. https://pagespeed.web.dev/ 접속 → 내 사이트 주소를 넣고 Analyze.
  2. 점수와 함께 LCP, TBT 같은 항목이 나온다. LCP(가장 큰 콘텐츠가 뜨는 시간)가 2.5초 이하면 양호, 4초를 넘으면 나쁨이다(web.dev 기준).
  3. "개선 기회(Opportunities)/진단(Diagnostics)" 목록에 "이미지 적절히 크기 조정", "사용하지 않는 JavaScript 줄이기" 같은 구체적 지적이 뜬다. 이게 범인 후보다.

크롬이 있으면 F12Lighthouse 탭 → Analyze page load 로도 같은 리포트를 볼 수 있다. 설치 필요 없다.

원인 1. 이미지가 너무 크다 (가장 흔함)

핸드폰으로 찍은 4MB 사진을 그대로 올리면 그 한 장 때문에 화면 전체가 느려진다. 0단계에서 "이미지" 지적이 떴다면 여기부터.

Next.js 사이트라면 <img> 대신 next/imageImage를 쓰는 것만으로 크기·화질·포맷(WebP/AVIF)이 자동으로 줄어든다. 화면 밖 이미지는 알아서 나중에 로딩(lazy)되고, width/height를 넣으면 자리를 미리 잡아 화면이 덜컹거리지 않는다.

jsx

import Image from 'next/image'

<Image src="/hero.png" width={1200} height={630} alt="대표 이미지" priority />
  • 맨 위에 보이는 대표 이미지 한 장에만 priority를 붙여 먼저 로딩한다(Next.js 16부터는 preload로 이름이 바뀌었다).
  • 나머지 이미지는 옵션을 안 줘도 알아서 지연 로딩된다.

AI 코딩 툴(Cursor·Lovable·v0 등)을 쓴다면 이렇게 시켜라: "모든 <img> 태그를 next/image의 Image 컴포넌트로 바꾸고, 맨 위 히어로 이미지에만 priority를 붙여줘."

Next.js가 아니어도 원리는 같다. 올리기 전에 이미지를 압축(예: squoosh.app)하고 WebP로 바꾼다.

원인 2. 데이터가 쌓여서 DB가 매번 테이블 전체를 훑는다

처음엔 빨랐는데 글·회원·주문이 수천 건 쌓이면서 조회가 느려졌다면 인덱스 없는 조회가 범인일 확률이 높다. 인덱스가 없으면 DB는 요청마다 테이블을 처음부터 끝까지 다 읽는다(전체 스캔).

Supabase(Postgres) 기준 해결:

  1. Supabase 대시보드 → Advisors → Query Performance(또는 Reports의 Query Performance)에서 느린 쿼리와 자주 걸리는 컬럼을 확인한다.
  2. 자주 걸러내거나 정렬하는 컬럼에 인덱스를 추가한다. SQL Editor에서:
sql

create index idx_posts_user_id on posts (user_id);
  1. 이미 운영 중이라 데이터가 많다면 쓰기 잠김을 피하려고 concurrently를 붙인다:
sql

create index concurrently idx_posts_created_at on posts (created_at);

Supabase 대시보드에는 어떤 인덱스를 만들면 좋은지 추천해주는 Index Advisor가 있다(Query Performance → 쿼리 선택 → Indexes 탭). 추천을 보고 위 SQL을 직접 실행하면 된다.

원인 3. 무료 요금제가 잠들었다 깨어난다 (첫 요청만 느림)

"오랜만에 들어가면 첫 로딩만 유독 느리고, 그 다음부터는 괜찮다" → 절전(콜드 스타트) 신호다.

  • Supabase 무료 플랜은 7일간 활동이 거의 없으면 프로젝트를 일시정지(pause) 할 수 있다. 정지되면 다시 깨어나는 첫 요청이 느리거나 실패한다. 대시보드에서 프로젝트를 Restore 하면 복구된다.
  • 서버리스 함수(Vercel 등)도 한동안 호출이 없으면 첫 실행이 느린 콜드 스타트가 생긴다.

대응: 방문이 뜸한 서비스라면 정지 전에 주기적으로 접속해 깨워두거나, 실제 트래픽이 있다면 유료 플랜으로 올려 상시 가동한다. "가끔 첫 요청만 느림"은 버그가 아니라 무료 절전의 정상 동작이라는 점을 알면 헛고생을 줄인다.

원인 4. 화면을 막는 무거운 스크립트·외부 위젯

최근에 채팅 위젯, 광고, 애널리틱스, 웹폰트, 유튜브 임베드 같은 걸 붙였다면 그게 첫 화면 렌더를 막고 있을 수 있다. web.dev는 <head>의 동기 스크립트와 렌더 차단 CSS가 표시를 지연시킨다고 지적한다.

  • 당장 필요 없는 외부 스크립트는 async/defer로 미루거나 페이지 하단에서 로딩한다.
  • PageSpeed의 "제3자 코드 영향(Reduce the impact of third-party code)" 항목에 뜬 스크립트가 후보다. 하나씩 빼보며 어느 게 원인인지 확인한다.

그래도 안 잡히면

  • 0단계 PageSpeed 리포트의 상위 3개 지적을 그대로 AI 코딩 툴에 붙여넣고 "이거 고쳐줘"라고 요청하라. Lighthouse 지적은 구체적이라 그대로 작업 지시가 된다.
  • "언제부터 느려졌나 / 그때 무엇을 바꿨나"를 떠올려 되돌려보는 게 가장 빠를 때가 많다(최근 배포·커밋 되돌리기).

다시 강조하면, 이 글은 "한 줄 고침"이 아니라 범인을 좁히는 체크리스트다. 측정(0단계) → 해당 원인만 적용 순서로 접근하라.