Local Storage의 용량은 얼마인가요?
Local Storage 용량: 브라우저별 저장 제한
Local Storage 용량 제한을 정확히 파악하면 웹 애플리케이션 개발 시 데이터 유실이나 브라우저 용량 초과 에러를 방지합니다. 안전하고 효율적인 클라이언트 사이드 데이터 관리를 위해 규격을 확인해야 합니다.
브라우저별 Local Storage 실제 용량 제한
웹 개발을 하다 보면 사용자 데이터를 클라이언트에 간단히 저장하기 위해 웹 스토리지(Web Storage) 기술을 자주 선택하게 됩니다. 그중에서도 가장 대중적인 Local Storage 용량은 일반적으로 도메인(Origin)당 5MB에서 10MB 사이로 제한되어 있습니다. 이 숫자는 고정된 절대 기준이라기보다는 브라우저 제조사들이 기기 메모리 남용을 막기 위해 설정해 둔 일종의 가이드라인에 가깝습니다. 예전 정보만 믿고 무턱대고 대용량 데이터를 밀어 넣다가는 실제 운영 환경에서 예상치 못한 크래시를 마주하기 십상입니다.
실제로 최신 브라우저 생태계를 살펴보면 용량 제한 정책이 조금씩 다릅니다. 구글 크롬(Chrome)과 마이크로소프트 엣지(Edge), 모질라 파이어폭스(Firefox)는 현재 도메인당 최대 10MB의 넉넉한 공간을 제공하는 반면, 애플의 사파리(Safari)와 오페라(Opera) 브라우저는 여전히 5MB 제한을 고수하고 있습니다. 이 용량은 프로토콜, 호스트 이름, 포트 번호가 결합된 각 웹사이트의 고유한 도메인 단위로 완전히 격리되어 누적 계산됩니다.
UTF-16 인코딩과 개발자가 체감하는 진짜 글자 수
여기서 많은 개발자가 놓치는 결정적인 함정이 바로 문자열 인코딩 방식입니다. 브라우저는 내부적으로 Local Storage의 데이터를 UTF-16 문자열 포맷으로 변환하여 저장합니다. 아시다시피 UTF-16 구조에서는 문자 1개당 기본적으로 2바이트(Bytes)의 물리적 메모리 공간을 차지하게 됩니다. 이 규칙은 영문자 알파벳 하나를 저장하든, 복잡한 한글 문자나 이모지를 저장하든 똑같이 적용됩니다.
이 개념을 글자 수 단위로 환산해 보면 실질적인 한계치가 명확해집니다. 사파리가 규정하는 5MB의 용량 제한은 물리적으로 약 5,242,880바이트를 의미하므로, 실제로 저장할 수 있는 최대 텍스트 길이는 약 2,621,440글자에 불과합니다. 반대로 10MB를 제공하는 크롬의 경우에는 대략 5,242,880글자까지 저장할 수 있는 셈입니다. 결국 우리가 제어할 수 있는 텍스트의 총길이는 브라우저가 명시하는 마케팅용 용량 수치의 정확히 절반 수준이라는 점을 기억해야 합니다. 제가 처음 이 사실을 모르고 대용량 JSON 데이터를 그대로 밀어 넣었을 때, 이론상 용량의 반도 안 찼는데 스토리지가 꽉 찼다고 뻗어버려서 밤새 원인을 찾으며 머리를 쥐어뜯었던 기억이 생생합니다.
로컬스토리지 용량 초과 에러(QuotaExceededError) 대응법
허용된 용량의 마지막 1바이트까지 모두 소진한 상태에서 localStorage.setItem() 메서드를 호출해 데이터 추가를 시도하면 브라우저는 가차 없이 예외를 발생시킵니다. 이때 마주하게 되는 에러가 바로 로컬스토리지 용량 초과 에러입니다. 이 에러는 웹 애플리케이션의 자바스크립트 실행 흐름을 완전히 중단시켜 버릴 수 있기 때문에, 서비스 안정성을 확보하려면 반드시 정교한 예외 처리 코드가 선행되어야 합니다. 그렇지 않으면 사용자의 장바구니 데이터나 임시 저장 글이 공중으로 날아가 버리는 대참사가 일어납니다.
데이터 오버플로우로 인한 크래시를 방지하는 가장 확실한 방어 기제는 자바스크립트의 try-catch 구문을 활용하는 것입니다.
단순히 에러가 났다고 사용자에게 경고창만 띄우기보다는, 앱 내부에서 오래된 데이터를 순차적으로 밀어내는 영리한 캐시 만료(Eviction) 알고리즘을 결합하는 방식이 현업에서 자주 쓰입니다.
다음은 실제 상용 서비스에서 안전하게 데이터를 적재할 때 사용하는 표준적인 에러 핸들링 구조입니다. javascript function safeSaveToLocalStorage(key, value) { try { localStorage.setItem(key, value); } catch (error) { if (error.name === QuotaExceededError || error.code === 22 || error.code === 1014) { // 용량 초과 발생 시 오래된 캐시 데이터를 일부 삭제하는 로직 pruneOldCacheData(); try { // 공간 확보 후 다시 저장을 시도 localStorage.setItem(key, value); } catch (retryError) { // 재시도마저 실패했을 때의 최종 예외 처리 logStorageFailure(retryError); } } else { // 보안 설정으로 스토리지 접근이 차단된 경우 등 기타 에러 처리 console.error(스토리지 접근 실패:, error); } } }
하지만 무작정 비우는 게 능사는 아닙니다. 데이터 청소 작업을 시작하기 전에 사용자가 시크릿 모드(Incognito)로 접속했는지도 따져봐야 합니다. 특히 iOS 환경의 사파리 시크릿 모드 같은 특수한 웹서핑 환경에서는 Local Storage의 기본 할당 용량 자체를 최초부터 0MB로 제한해 두는 경우가 허다합니다. 이 경우 데이터 가득 참 유무와 상관없이 첫 번째 쓰기 시도부터 곧바로 에러가 터지기 때문에, 사전에 더미 데이터를 썼다 지우는 방식으로 스토리지 가용성을 체크하는 유효성 검사 루틴을 전역에 배치해 두는 것이 좋습니다. 대다수 가이드는 무조건 다 지우라고만 조언하지만, 실무에서는 사용자의 중요 설정값까지 날려버리면 민원이 폭주하므로 로그 데이터처럼 날아가도 무방한 비핵심 요소부터 골라내어 지우는 정밀함이 요구됩니다.
5MB의 한계를 넘어선 대용량 클라이언트 저장소 대체안
웹 앱의 규모가 커지고 오프라인 동작 기능이나 이미지, 미디어 파일 등의 리소스를 로컬 환경에 직접 구조화하여 보관해야 할 때는 Local Storage의 태생적인 한계가 도드라집니다. 동기식(Synchronous)으로 작동하는 특성 탓에 메인 스레드를 붙잡아 화면을 버벅이게 만들 뿐만 아니라, 오직 단순한 문자열 구조만 수용할 수 있기 때문입니다. 이럴 때는 브라우저가 제공하는 대용량 전용 비동기 데이터베이스 시스템인 IndexedDB로 고개를 돌려야 할 때입니다.
IndexedDB는 Local Storage와 비교가 불가능할 정도로 광활한 저장 공간을 선사합니다. 기기의 물리적인 하드디스크 남은 용량에 연동되어 작동하기 때문에, 브라우저와 클라이언트 환경에 따라 수백 MB에서 수 GB 단위의 구조화된 바이너리 데이터를 아무런 제약 없이 트랜잭션 기반으로 안전하게 다룰 수 있게 됩니다.
웹 브라우저 저장소 핵심 스펙 비교
적재하려는 데이터의 성격과 용량 규모에 따라 가장 올바른 브라우저 저장 매체를 선택할 수 있도록 핵심 지표들을 비교해 드립니다.Cookie
- 매 HTTP 요청마다 서버로 자동 전송되어 대역폭을 소모함
- 사용자 세션 인증 토큰, 식별용 식별자 저장
- 단순 문자열 텍스트만 지원
- 도메인당 약 4KB 내외로 매우 협소함
Local Storage ⭐
- 클라이언트 브라우저 내부에만 머물며 자동 전송되지 않음
- 다크모드 설정, 자동 로그인 여부, UI 커스텀 설정값
- 오직 문자열 데이터만 수용 (객체는 직렬화 필요)
- 브라우저 환경에 따라 도메인당 5MB에서 10MB 제공
IndexedDB
- 완전한 로컬 격리형 비동기 데이터베이스로 전송 안 됨
- 오프라인 웹 앱 데이터 캐싱, 복잡한 구조의 클라이언트 DB
- 문자열은 물론 객체, 대용량 바이너리 Blob 데이터 지원
- 기기 여유 디스크 공간의 50% 이상 (수백 MB에서 수 GB 이상)
성공적인 대용량 데이터 마이그레이션: 민우의 프론트엔드 최적화 스토리
서울의 한 물류 스타트업에서 근무하는 3년 차 프론트엔드 개발자 민우 씨는 오프라인 환경에서도 작동하는 웹 대시보드를 구축하다가 큰 난관에 봉착했습니다. 사용자가 수십 개의 물품 테이블 페이지를 넘겨가며 조회할 때마다 렌더링 속도가 눈에 띄게 무거워졌고 데이터가 누적되면 화면이 완전히 굳어버렸습니다.
민우 씨는 초기에 구현 속도를 높이기 위해 모든 대시보드 캐시 데이터를 무작정 Local Storage에 집어넣었습니다. 하지만 테이블 데이터가 점차 쌓이면서 사파리 브라우저를 쓰던 현장 현업 팀원들의 화면에 원인 모를 자바스크립트 먹통 현상과 함께 먹통 에러 코드가 무더기로 출력되기 시작했습니다.
하루 꼬박 로그를 추적한 끝에 민우 씨는 UTF-16 인코딩 방식 때문에 실제 허용 용량이 예상했던 5MB의 반 토막 수준인 2.5MB 근처에서 제한되어 에러가 터졌다는 사실을 알아냈습니다. 그는 불필요하게 가득 찬 스토리지 텍스트 데이터를 무작정 비우기보다 대용량 구조화 객체를 비동기로 분리 처리해야 함을 깨달았습니다.
결국 민우 씨는 기존 Local Storage 시스템을 전면 폐기하고 바이너리 적재가 용이한 IndexedDB 기반으로 저장소 아키텍처를 전면 전환했습니다. 마이그레이션 이후 단 한 건의 용량 초과 에러도 발생하지 않았으며 데이터 조회 레이턴시 성능이 대폭 개선되어 현장 대시보드 로딩 속도가 이전 대비 체감될 정도로 민첩해졌습니다.
요약 & 결론
브라우저별 임계 한계선인 5MB와 10MB를 명확히 숙지하세요크롬과 파이어폭스는 10MB까지 수용하지만 사파리와 오페라는 여전히 5MB가 한계이므로 크로스 브라우징 서비스를 설계할 때는 항상 최저 기준인 5MB에 맞춰 설계해야 안전합니다.
글자 수 계산 시 UTF-16 인코딩의 물리 바이트 손실을 고려하세요텍스트 데이터 저장 시 모든 문자가 2바이트로 계산되므로 실질적으로 개발자가 적재 가능한 최대 텍스트 길이는 브라우저 스펙상 표시된 허용 용량의 절반 수치로 줄어듭니다.
용량 한계 오버플로우에 대비한 try-catch 예외 처리를 필수로 배치하세요스토리지가 가득 찬 시점에 발생하는 QuotaExceededError 예외는 전체 서비스 스크립트를 중단시킬 수 있으므로 쓰기 수식 장치마다 안전장치 코드를 씌우고 지속적인 데이터 만료 규칙을 도입해야 합니다.
추가 참고
로컬 스토리지에 데이터를 저장할 때 서브 도메인 간에 공간이 공유되나요?
아닙니다. Local Storage는 철저하게 프로토콜, 호스트, 포트가 완벽히 일치해야 하는 동일 출처 정책을 따릅니다. 따라서 본 도메인과 서브 도메인은 서로 다른 스토리지 공간을 할당받아 용량이 따로 계산되며 데이터 접근도 기본적으로 제한됩니다.
브라우저 시크릿 모드에서는 로컬 스토리지 용량이 어떻게 변하나요?
최신 브라우저들의 시크릿 모드 환경에서는 Local Storage 사용이 일시적으로 허용되지만 브라우저 창이나 탭을 완전히 닫는 순간 저장되었던 모든 데이터가 자동으로 소멸합니다. 특히 과거 특정 모바일 환경이나 사파리 일부 버전에서는 가용 용량 자체를 최초부터 제로로 차단하여 쓰기 시 즉시 오류가 날 수 있습니다.
로컬 스토리지의 남은 가용 용량을 코드로 직접 정확히 조회할 수 있나요?
브라우저 API 내부에는 현재 남은 용량을 숫자로 직접 반환해 주는 표준 메서드가 존재하지 않습니다. 우회적인 방법으로 현재 스토리지에 저장된 모든 키와 값의 길이를 반복문으로 전부 더한 뒤 가상 용량 한계치인 5MB나 10MB에서 차감하여 대략적인 잔여 공간을 추정 계산해야 합니다.
답변에 대한 의견:
의견을 주셔서 감사합니다! 여러분의 의견은 향후 답변을 개선하는 데 매우 중요합니다.