콘텐츠로 이동

Web Storage: localStorage ~ IndexedDB

브라우저에는 서버를 거치지 않고 데이터를 저장할 수 있는 여러 저장소가 있습니다. 용도와 생명주기에 따라 localStorage, sessionStorage, IndexedDB를 적절히 선택해야 합니다.

브라우저에 영구적으로 데이터를 저장합니다. 브라우저별로 보통 5MB 정도의 용량을 제공합니다.

localStorage.setItem(key, value);
localStorage.getItem(key);
localStorage.removeItem(key);
  • 값은 항상 문자열로 저장됩니다. 객체나 배열을 저장하려면 JSON.stringify/JSON.parse를 사용해야 합니다.
  • 민감한 정보는 저장하면 안 됩니다. 누구나 DevTools로 접근 가능합니다.
  • 다크 모드 설정 저장 등에 주로 활용됩니다. React에서는 Context API와 연동하는 패턴이 일반적입니다.

같은 페이지를 여러 탭으로 열었을 때, 한 탭에서 localStorage를 변경하면 다른 탭에서도 반영해야 하는 경우가 있습니다. storage 이벤트를 활용합니다.

function applySavedTheme() {
const savedTheme = localStorage.getItem("theme");
if (savedTheme === "dark") {
document.body.classList.add("dark-mode");
toggleButton.textContent = "Light Mode";
return;
}
document.body.classList.remove("dark-mode");
toggleButton.textContent = "Dark Mode";
}
window.addEventListener("storage", (e) => {
if (e.key === "theme") {
applySavedTheme();
}
});

storage 이벤트는 같은 출처의 다른 탭에서 변경이 발생했을 때만 트리거됩니다.

localStorage와 API는 거의 동일하지만 생명주기가 다릅니다.

  • 새 탭이나 새 창에서는 공유되지 않습니다.
  • 탭을 닫으면 데이터가 초기화됩니다.
  • 검색 내역, 광고 모달 표시 여부 등 세션 단위로 관리할 데이터에 적합합니다.
const openAdModal = () => {
if (Boolean(sessionStorage.getItem("shownWarning"))) return;
Modal.open();
sessionStorage.setItem("shownWarning", true);
};
openAdModal();

새로고침 후에도 데이터가 유지되지만, 탭을 닫으면 사라지므로 요구사항이 명확해야 합니다.

localStorage보다 훨씬 큰 용량을 저장할 수 있는 브라우저 내장 데이터베이스입니다. 비동기 API 기반이며, 트랜잭션 단위로 동작합니다.

const open = indexedDB.open("IndexedDB", 1); // 두 번째 인자는 버전
open.onupgradeneeded = () => {
const db = open.result;
db.createObjectStore("MyUserStore", { keyPath: "id" });
};
open.onsuccess = () => {
console.log("opened");
const db = open.result;
const transaction = db.transaction("MyUserStore", "readwrite");
const store = transaction.objectStore("MyUserStore");
store.put({ id: 1, username: "sojeong", age: 28 });
const user1 = store.get(1);
user1.onsuccess = () => {
console.log(user1.result);
};
};
open.onerror = () => {
console.log("error occurred");
};

콜백 기반 API라 사용법이 다소 복잡합니다. 실무에서는 idb 같은 래퍼 라이브러리를 사용하는 경우가 많습니다.

항목localStoragesessionStorageIndexedDB
용량~5MB~5MB수백 MB 이상
생명주기영구탭/세션 단위영구
API동기동기비동기
데이터 형식문자열문자열구조화된 객체
사용처설정, 테마임시 상태대용량 캐시, 오프라인