Web Storage API는 무엇이고 localStorage와 sessionStorage는 언제 어떻게 써야 할까
프론트엔드 개발을 하다 보면 브라우저 안에 무언가를 저장하고 싶은 순간이 자주 옵니다.
- 다크모드 설정을 유지하고 싶을 때
- 최근 본 탭 상태를 기억하고 싶을 때
- 폼 입력 중간값을 잠깐 저장하고 싶을 때
- 새로고침 뒤에도 일부 상태를 복원하고 싶을 때
이럴 때 가장 먼저 떠오르는 것이 보통 localStorage나 sessionStorage입니다.
그런데 막상 쓰려고 하면 헷갈리는 지점도 많습니다.
- 둘은 정확히 무엇이 다른지
- 어떤 데이터까지 넣어도 되는지
- 객체는 어떻게 저장하는지
- 탭을 닫으면 어떻게 되는지
- 인증 토큰 같은 민감한 값도 넣어도 되는지
이 글에서는 Web Storage API를 아래 흐름으로 정리해보겠습니다.
Web Storage API는 무엇인지localStorage와sessionStorage는 무엇이 다른지- 언제 어떤 데이터를 저장하면 좋은지
- 실무에서 자주 하는 실수는 무엇인지
한눈에 보면
먼저 짧게 정리하면 이렇습니다.
Web Storage API는 브라우저에 key-value 형태로 문자열 데이터를 저장하는 API입니다.localStorage는 비교적 오래 남고,sessionStorage는 탭 세션에 더 가깝습니다.- 둘 다 자바스크립트에서 직접 읽고 쓸 수 있습니다.
- 사용자 설정, 임시 UI 상태, 비민감한 캐시 데이터에 자주 쓰입니다.
- 하지만 민감한 인증 정보 저장소로는 보안 관점을 더 신중히 봐야 합니다.
즉, Web Storage API는 브라우저 안에 간단한 상태를 남길 수 있는 편한 도구이지만, 무엇을 저장해도 되는 만능 저장소는 아닙니다.
Web Storage API는 정확히 무엇일까?
브라우저에서는 보통 아래 두 객체를 통해 접근합니다.
window.localStorage;
window.sessionStorage;이 두 객체는 공통적으로:
- key-value 구조를 가지고
- 문자열 기반으로 저장되며
- 브라우저에서 쉽게 읽고 쓸 수 있습니다
가장 기본적인 사용은 이렇게 생겼습니다.
localStorage.setItem('theme', 'dark');
const theme = localStorage.getItem('theme');
console.log(theme); // dark즉, Web Storage API는 브라우저 안에 간단한 문자열 상태를 저장하는 기본 API라고 보면 됩니다.
왜 Web Storage를 쓸까?
가장 큰 이유는 간단합니다. 새로고침 이후에도 일부 상태를 유지하기 쉽기 때문입니다.
예를 들어:
- 다크모드 설정
- 사용자가 마지막으로 본 탭
- 검색 필터 일부
- 온보딩 닫힘 여부
같은 값은 서버에 저장할 만큼 무겁지는 않지만, 메모리 state에만 두면 새로고침 시 사라질 수 있습니다.
이때 Web Storage는 꽤 편합니다.
즉, 이 API는 "서버 DB"와 "컴포넌트 메모리 state" 사이 어딘가에 있는 가벼운 브라우저 저장소에 가깝습니다.
localStorage와 sessionStorage는 무엇이 다를까?
둘 다 비슷해 보여도 사용성이 다릅니다.
localStorage
- 브라우저에 비교적 오래 남습니다
- 새로고침해도 유지됩니다
- 브라우저를 닫았다가 다시 열어도 남는 경우가 일반적입니다
즉, 사용자가 다음 방문 때도 유지되면 좋은 값에 더 잘 맞습니다.
sessionStorage
- 탭 세션에 더 가깝습니다
- 새로고침해도 유지될 수 있지만
- 탭을 닫으면 사라지는 방향에 가깝습니다
즉, 현재 탭 안에서만 잠깐 유지되면 좋은 값에 더 잘 맞습니다.
짧게 비교하면 아래처럼 볼 수 있습니다.
| 항목 | localStorage |
sessionStorage |
|---|---|---|
| 새로고침 후 유지 | 유지됨 | 유지됨 |
| 탭 닫은 뒤 유지 | 대체로 유지됨 | 보통 사라짐 |
| 탭 간 공유 감각 | 더 있음 | 탭 단위에 가까움 |
| 잘 맞는 용도 | 설정, 선호값, 가벼운 캐시 | 임시 입력 상태, 탭 전용 흐름 |
즉, 두 저장소의 본질적 차이는 보안보다 수명과 범위에 더 가깝습니다.
기본 메서드는 어떻게 생겼을까?
공통적으로 자주 쓰는 메서드는 아래와 같습니다.
1. setItem
localStorage.setItem('theme', 'dark');값을 저장합니다.
2. getItem
const theme = localStorage.getItem('theme');값을 읽습니다. 없으면 null이 옵니다.
3. removeItem
localStorage.removeItem('theme');특정 key를 제거합니다.
4. clear
localStorage.clear();저장소 전체를 비웁니다.
5. key, length
console.log(localStorage.length);
console.log(localStorage.key(0));저장된 key 개수와 특정 인덱스의 key를 볼 수 있습니다.
즉, API 자체는 매우 단순합니다. 어려운 부분은 저장소 사용법보다 무엇을 저장해야 하는지 판단하는 것에 더 가깝습니다.
객체는 어떻게 저장할까?
여기서 자주 하는 실수가 있습니다. Storage는 문자열 기반이라서 객체를 그대로 넣을 수 없습니다.
예를 들어 이런 코드는 기대와 다르게 동작합니다.
localStorage.setItem('user', { id: 1, name: 'Marco' } as unknown as string);그래서 보통은 JSON.stringify와 JSON.parse를 같이 씁니다.
const user = { id: 1, name: 'Marco' };
localStorage.setItem('user', JSON.stringify(user));
const rawUser = localStorage.getItem('user');
const parsedUser = rawUser ? JSON.parse(rawUser) : null;즉, 객체나 배열은 직렬화해서 저장하고, 읽을 때 다시 파싱하는 흐름이 기본입니다.
언제 localStorage가 잘 맞을까?
대표적으로 아래 같은 값이 잘 맞습니다.
1. 사용자 설정
localStorage.setItem('theme', 'dark');
localStorage.setItem('language', 'ko');이런 값은 다음 방문에도 유지될수록 좋습니다.
2. 온보딩/공지 닫힘 여부
localStorage.setItem('hideOnboarding', 'true');사용자 경험상 반복 노출을 줄이고 싶을 때 자연스럽습니다.
3. 비민감한 가벼운 캐시
예를 들어:
- 마지막 검색어
- 최근 본 카테고리
- 정렬 기준
같은 값은 localStorage와 잘 맞는 경우가 많습니다.
즉, localStorage는 오래 기억해도 되는 비민감한 브라우저 개인화 값에 잘 맞습니다.
언제 sessionStorage가 잘 맞을까?
대표적으로 아래 같은 경우입니다.
1. 탭 단위 임시 상태
예를 들어 멀티스텝 폼에서:
sessionStorage.setItem('signupStep', '2');같이 현재 탭 흐름 안에서만 유지하고 싶은 값입니다.
2. 새로고침 복원용 임시 데이터
탭은 유지하되 브라우저를 완전히 닫으면 굳이 남지 않아도 되는 값에 잘 맞습니다.
3. 탭 간 섞이면 안 되는 상태
예를 들어 같은 서비스를 여러 탭에서 열었을 때, 탭마다 다른 임시 흐름을 가져야 한다면 sessionStorage가 더 자연스러울 수 있습니다.
즉, sessionStorage는 지속성보다 현재 탭 문맥 유지에 더 어울립니다.
storage 이벤트는 언제 쓸까?
localStorage를 다룰 때 가끔 유용한 기능입니다.
다른 탭에서 저장소 값이 바뀌면 이벤트를 감지할 수 있습니다.
window.addEventListener('storage', (event) => {
console.log(event.key, event.oldValue, event.newValue);
});예를 들어:
- 한 탭에서 로그아웃하면 다른 탭도 반응하게 하거나
- 테마 변경을 다른 탭에 반영하고 싶을 때
같은 흐름에 활용할 수 있습니다.
즉, Web Storage는 단순 저장소일 뿐 아니라 탭 간 간단한 상태 동기화 힌트로도 쓸 수 있습니다.
무엇을 저장하면 안 될까?
이 부분이 실무에서 중요합니다.
1. 민감한 인증 정보
예를 들어:
- 장기
refresh token - 민감한 세션 식별자
- 개인정보가 많이 담긴 값
같은 것은 더 신중히 봐야 합니다.
이유는 단순합니다.
localStorage,sessionStorage는 자바스크립트에서 읽을 수 있고- XSS가 발생하면 탈취 표면이 커질 수 있기 때문입니다
즉, 브라우저 저장소는 편하지만 민감한 장기 토큰 저장소로는 보수적으로 판단해야 합니다.
2. 너무 큰 데이터
브라우저 저장소는 무한하지 않습니다.
또한 너무 큰 데이터를 넣으면:
- 직렬화 비용이 커지고
- 읽기/쓰기 비용이 늘고
- 유지보수가 어려워질 수 있습니다
즉, 큰 캐시나 대용량 데이터는 다른 저장 전략이 더 맞을 수 있습니다.
3. 진실의 원천이 되어야 하는 비즈니스 데이터
예를 들어 서버와 정합성이 중요한 데이터를 브라우저 저장소만 믿고 운영하면 쉽게 어긋날 수 있습니다.
Web Storage는 어디까지나 보조 저장소에 더 가깝습니다.
React나 Next.js에서는 무엇을 조심해야 할까?
여기가 실무에서 꽤 중요합니다.
1. 서버 환경에서는 바로 접근할 수 없다
localStorage와 sessionStorage는 브라우저에서만 존재합니다.
즉, SSR이나 서버 컴포넌트에서는 바로 접근하면 안 됩니다.
console.log(localStorage.getItem('theme'));이런 코드는 클라이언트 실행 시점에만 안전합니다.
그래서 보통:
useEffect안에서 읽거나- 이벤트 핸들러 안에서 쓰거나
- 클라이언트 전용 컴포넌트에서만 사용하는 식으로
경계를 나눕니다.
2. 초기 렌더와 hydration 차이
예를 들어 서버에서는 테마 정보를 모르고, 클라이언트에서만 localStorage를 읽는다면 초기 UI 깜빡임이 생길 수 있습니다.
즉, 저장소 사용은 단순 API 호출 문제가 아니라 초기 렌더 전략과도 연결됩니다.
3. 상태 동기화 기준
React state와 저장소를 양방향으로 무작정 동기화하면 오히려 복잡해질 수 있습니다.
그래서 보통은:
- 초기값만 저장소에서 읽거나
- 특정 이벤트 시점에만 저장하거나
- 커스텀 훅으로 읽기/쓰기 규칙을 묶는 편이 더 안정적입니다
자주 하는 실수
정리하면 아래 실수가 정말 자주 나옵니다.
- 객체를 그대로 저장하려고 한다
- 없는 값이
null로 올 수 있다는 점을 놓친다 - 민감한 토큰을 쉽게 저장해도 된다고 생각한다
- 서버 환경에서 바로
localStorage를 읽는다 - 브라우저 저장소를 서버 데이터의 진실 원천처럼 쓴다
clear()를 너무 넓게 써서 다른 값까지 같이 지운다
즉, Web Storage는 쉬워 보여도 수명, 직렬화, 브라우저 전용 환경, 보안 특성을 같이 봐야 안정적으로 쓸 수 있습니다.
실무 체크리스트
실제로 적용할 때는 아래 질문으로 빠르게 점검하면 도움이 됩니다.
- 이 값은 새로고침 뒤에도 유지되어야 하는가?
- 다음 방문 때도 남아야 하는가, 현재 탭에만 있으면 되는가?
- 자바스크립트에서 읽혀도 괜찮은 비민감한 값인가?
- 객체라면 직렬화/역직렬화 규칙이 명확한가?
- 서버 렌더링 환경과 충돌하지 않는가?
이 질문에 답하면 localStorage와 sessionStorage 중 무엇이 더 맞는지도 훨씬 선명해집니다.
정리하면
Web Storage API를 한 줄로 줄이면, 브라우저 안에 문자열 기반 상태를 저장하고 복원할 수 있게 해주는 기본 저장소 API입니다.
실무 기준으로 기억할 핵심은 이렇습니다.
localStorage는 더 오래 남는 설정/선호값에 잘 맞고sessionStorage는 현재 탭 문맥의 임시 상태에 더 잘 맞으며- 둘 다 문자열 기반이라 직렬화가 필요하고
- 둘 다 자바스크립트 접근이 가능하므로 민감 정보 저장은 더 신중해야 합니다
브라우저 저장소는 프론트엔드에서 정말 자주 쓰이는 기본기입니다. 그래서 이 API를 잘 이해하면 단순한 설정 저장뿐 아니라, 상태 복원, 탭 간 동기화, 렌더링 전략까지 더 안정적으로 설계할 수 있게 됩니다.
