Homada
블로그 목록으로 돌아가기
2026-07-17작성자: 호마다 테크 랩스

대시보드가 유독 느렸던 이유: getUser() 호출 횟수를 세어보고 알았다

#Nextjs#Supabase#성능최적화#ServerComponents#인증
대시보드가 유독 느렸던 이유: getUser() 호출 횟수를 세어보고 알았다

지난달부터 "대시보드 아무 메뉴나 눌러도 좀 느린 것 같다"는 이야기가 몇 번 나왔습니다. 처음엔 대수롭지 않게 넘겼는데, 실제로 개발자 도구를 켜고 확인해보니 페이지 하나 들어가는 데 3초 넘게 걸리는 경우가 있었습니다. 쿼리 몇 개 늘어난 정도로는 설명이 안 되는 수치였습니다.

원인을 찾고 보니 허무할 정도로 단순했습니다. 페이지 하나를 열 때마다 같은 인증 확인 요청을 4~6번씩 반복하고 있었습니다.

layout와 page가 각자 auth 서버를 호출하던 구조(왼쪽)와 cache()로 요청을 하나로 묶은 구조(오른쪽) 비교

증상: 쿼리는 안 늘었는데 네트워크 요청은 늘어 있었다

먼저 의심한 건 DB 쿼리였습니다. 대시보드가 건물별 정산 데이터를 여러 테이블에서 긁어오다 보니 N+1 문제가 생겼을 거라고 짐작했죠. 그런데 Network 탭을 열어놓고 대시보드로 이동해보니, DB 쿼리보다 눈에 띄는 건 auth/v1/user로 나가는 요청이 한 페이지에서 여러 번 찍힌다는 점이었습니다.

Next.js App Router에서는 layout.tsxpage.tsx가 각각 독립된 서버 컴포넌트로 렌더링됩니다. 그리고 저희 코드는 이 둘 모두에서 로그인 여부를 확인하려고 각자 supabase.auth.getUser()를 부르고 있었습니다.

// dashboard/layout.tsx
const { data: { user } } = await supabase.auth.getUser();

// dashboard/page.tsx (같은 요청, 다른 컴포넌트)
const { data: { user } } = await supabase.auth.getUser();

getUser()는 로컬에 있는 JWT를 그냥 디코딩하는 함수가 아닙니다. Supabase Auth 서버까지 갔다가 오는 실제 네트워크 왕복입니다. 그런데 대시보드 하위 라우트 대부분이 layout과 page 양쪽에서 이 함수를 부르고 있었고, 여기에 앞단 미들웨어의 세션 체크까지 더하면 페이지 하나 들어갈 때 인증 서버 왕복이 4~6번씩 겹쳐서 발생하고 있었습니다. 화면이 그려지기도 전에 말이죠.

고친 방법: 캐시가 아니라 "요청 하나 안에서만" 기억하기

여기서 가장 먼저 든 생각은 "그럼 유저 정보를 어딘가에 캐싱해두면 되지 않나"였는데, 이게 오히려 위험한 선택지였습니다. 모듈 최상단에 변수 하나 두고 거기에 담아두는 방식은, 서버리스 함수 인스턴스가 다음 요청에서 재사용될 때 이전 사용자의 세션 정보가 다음 사용자에게 그대로 노출될 수 있습니다. 인증 정보는 요청이 끝나면 반드시 같이 사라져야 합니다.

그래서 쓴 게 React의 cache() 함수입니다. 이건 전역 캐시가 아니라 요청 하나 범위 안에서만 살아있는 메모이제이션입니다. 같은 요청 안에서 여러 컴포넌트가 같은 함수를 불러도 실제 실행은 1번만 되고, 요청이 끝나면 그 결과는 같이 사라집니다.

// src/utils/supabase/server.ts
import { cache } from "react";

export const getAuthUser = cache(async () => {
  const supabase = await createClient();
  return supabase.auth.getUser();
});

그리고 layout.tsx, page.tsx에서 기존 supabase.auth.getUser() 호출부를 getAuthUser()로 바꿨습니다.

- const { data: { user } } = await supabase.auth.getUser();
+ const { data: { user } } = await getAuthUser();

대시보드와 관리자 라우트 아래 layout·page 15개 파일이 대상이었습니다. 코드 자체는 크게 어렵지 않은데, 두 가지는 일부러 손대지 않았습니다.

첫째, 미들웨어에 해당하는 proxy.ts는 그대로 뒀습니다. Edge 런타임은 실행 컨텍스트가 달라서 위 cache()가 거기까지 이어지지 않습니다. 억지로 캐시를 공유하려 하기보다는 별개 검증 지점으로 남겨두는 편이 안전하다고 판단했습니다.

둘째, Server Action이나 API 라우트 내부에서 부르는 getUser()는 이번 범위에서 뺐습니다. 렌더링 경로(layout/page)에서의 중복만 해결하는 걸 1차 목표로 잡았고, 나머지는 실제로 문제가 있는지 확인한 다음에 손대기로 했습니다.

인증과 맞닿은 코드라 머지 전에 별도로 보안 리뷰를 한 번 더 거쳤습니다. 세션이 다른 요청으로 새어나갈 경로가 없는지, 권한 판단 자체는 여전히 매번 새로 이뤄지는지(캐시가 인가 로직을 건너뛰게 만들지는 않는지) 확인하는 게 핵심이었습니다. 유닛 테스트와 관련 E2E까지 통과한 뒤에야 머지했습니다.

확인 사살: Server Action 쪽은 뒤져봤는데 문제가 없었다

1차 수정을 배포하고 나서, 남겨뒀던 Server Action 쪽도 혹시나 하는 마음에 다시 훑어봤습니다. 결과는 "문제 없음"이었습니다. 각 액션 함수 안에서 getUser()는 정확히 한 번씩만 호출되고 있었고, 같은 요청 안에서 중복 호출되는 패턴은 없었습니다. 의심 가는 곳을 뒤졌는데 아무 것도 안 나온 셈인데, 이것도 나름 의미 있는 결과라고 생각합니다. 적어도 다음에 이 코드를 보는 사람이 같은 의심을 반복할 필요는 없어졌으니까요.

그런데 이걸 고치고도 뭔가 더 남아 있었다

여기서 끝났으면 좋았겠지만, 배포 후에도 로딩이 눈에 띄게 빠르다고 하기엔 애매했습니다. 다시 파고들다가 두 가지를 더 찾았습니다.

하나는 인덱스 누락이었습니다. property_verifications 테이블의 user_id/building_id, subscription_payments 테이블의 user_id는 FK로 참조는 걸려 있었지만 정작 인덱스가 없어서, 라운지·결제내역 페이지에 들어갈 때마다 시퀀셜 스캔을 타고 있었습니다.

다른 하나는 좀 더 근본적인 문제였는데, Vercel 함수 리전과 Supabase 프로젝트 리전이 아예 다른 대륙에 있었습니다. Vercel은 iad1(미국 동부), Supabase는 ap-southeast-1(싱가포르)이었습니다. 코드에서 아무리 요청 횟수를 줄여도, 요청 하나하나가 지구 반 바퀴를 돌아야 한다면 거기서 이미 손해를 보고 시작하는 셈입니다. Vercel 함수 리전을 Supabase 쪽에 맞춰 옮기고 나서야 체감 속도가 한 번 더 달라졌습니다.

돌아보면 순서가 조금 아쉽습니다. 리전부터 확인했으면 더 빨리 끝났을 수도 있는 문제인데, 눈에 보이는 중복 호출부터 잡다 보니 리전 문제는 그 다음에야 발견했습니다.

결과

수정 전후를 정확한 숫자로 비교할 만한 벤치마크 환경을 따로 만들어두진 않았습니다. 대신 실제 운영 환경에서 개발자 도구 Network 탭을 열어 확인했고, 대시보드 진입 시 나가던 인증 서버 왕복이 눈에 띄게 줄어든 것과 체감 로딩 속도가 함께 개선된 것을 확인했습니다.

정리하면 이번에 손을 댄 지점은 세 가지였습니다.

원인 조치
layout·page가 각자 getUser() 호출 React cache()로 요청 스코프 메모이제이션
일부 테이블 인덱스 누락 누락된 컬럼에 인덱스 추가
Vercel-Supabase 리전 불일치 Vercel 함수 리전을 Supabase와 동일 리전으로 이동

코드 한 줄만 고쳐서 극적으로 좋아지는 경우는 생각보다 드물고, 이번에도 그랬습니다.

더 읽을거리

같은 요청 안에서 비동기 호출이 겹치는 문제는 사실 프론트엔드에서도 자주 만나는 이슈입니다. 컴포넌트 여러 개가 동시에 같은 작업을 벌이다가 경합이 생기는 케이스를 다룬 글을 최근에 봤는데, 결이 비슷해서 도움이 될 것 같습니다.


호마다(HOMADA)는 다세대·빌라 임대관리 SaaS를 Next.js와 Supabase로 운영하면서 나온 문제와 해결 과정을 이런 식으로 가끔 정리해서 남기고 있습니다. 비슷한 스택으로 서비스를 운영 중이거나, 저희 아키텍처에 대해 더 궁금한 점이 있다면 호마다 홈페이지에서 문의해 주세요.


소형 공동주택 건물주 필수 솔루션

골치 아픈 관리비 수납과 연체 문자 독촉, 이제 호마다로 자동화하세요.

카카오 알림톡 무제한 발송과 월세 자동 수납 기능을 한 달 커피 두 잔 값에 제공해 드립니다. 카드 등록 없이 1개월 무료 체험해 보세요!