Moment.js를 떠나보낼 시간: Day.js, Luxon, date-fns 완벽 비교 및 마이그레이션 가이드
과거 자바스크립트 생태계에서 날짜와 시간을 다루는 표준은 의심의 여지 없이 Moment.js였습니다. 하지만 이제는 Moment.js를 프로젝트에서 걷어내야 할 때입니다. 2020년, Moment.js 팀은 공식적으로 Project Status 페이지를 통해 신규 기능 개발 중단과 유지보수 모드 진입을 선언했습니다.
이번 포스팅에서는 왜 Moment.js를 더 이상 사용하면 안 되는지, 그리고 그 대안으로 떠오른 세 가지 강자(Day.js, Luxon, date-fns)의 특징과 차이점을 심층 분석해 보겠습니다.
목차
- Moment.js를 더 이상 사용하지 않는 이유
- 대안 1: 가볍고 익숙한 Day.js
- 대안 2: Moment의 진화형 Luxon
- 대안 3: 함수형 프로그래밍의 정수 date-fns
- 한눈에 비교하는 라이브러리 선택 가이드
- 마치며: 어떤 라이브러리를 선택해야 할까?
Moment.js를 더 이상 사용하지 않는 이유
가장 큰 이유는 번들 사이즈와 가변성(Mutability) 때문입니다.
- Tree-shaking 미지원: Moment.js는 모든 로케일(Locale) 정보를 한꺼번에 포함하려는 경향이 있어, 사용하지 않는 기능까지 번들에 포함됩니다. 이는 현대 웹 성능 최적화에 큰 걸림돌이 됩니다.
- Mutable API: Moment 객체는 값을 변경하면 원본 데이터가 바뀝니다. 예를 들어
date.add(1, 'day')를 수행하면 원본date값이 변하게 되어 예측 불가능한 버그를 유발합니다. - 현대적 표준 미비: 객체 지향적 설계보다는 오래된 구조를 유지하고 있어, 최신 브라우저의
IntlAPI를 제대로 활용하지 못합니다.
대안 1: 가볍고 익숙한 Day.js
Day.js는 Moment.js와 거의 동일한 API 구조를 가지면서도 크기는 획기적으로 줄인(2KB 미만) 라이브러리입니다.
주요 특징
- 최소화된 크기: 핵심 엔진이 매우 가볍고, 필요한 기능(RelativeTime, Timezone 등)은 별도의 플러그인으로 설치하여 사용합니다.
- Immutability: 모든 연산은 새로운 객체를 반환하므로 부작용이 없습니다.
- Moment와의 호환성: API가 매우 유사하여 마이그레이션 비용이 가장 적습니다.
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
// 플러그인 기반 확장
dayjs.extend(relativeTime);
const now = dayjs();
const nextWeek = now.add(7, 'day'); // 원본 now는 변하지 않음
console.log(now.format('YYYY-MM-DD'));
console.log(nextWeek.fromNow()); // 플러그인을 통한 상대 시간 출력
대안 2: Moment의 진화형 Luxon
Luxon은 Moment.js를 만든 개발자 중 한 명이 만든 라이브러리입니다. Moment의 단점을 보완하면서 현대적인 요구사항을 반영했습니다.
주요 특징
- Intl API 기반: 브라우저 기본 국제화 API를 활용하므로 로케일 파일을 따로 관리할 필요가 거의 없습니다.
- 강력한 타임존 관리: 타임존과 일광 절약 시간(DST) 처리에 매우 특화되어 있습니다.
- 명확한 데이터 타입:
DateTime,Duration,Interval등 목적에 맞는 객체를 명확히 구분합니다.
import { DateTime } from 'luxon';
// 브라우저의 Intl API를 사용하여 한국어 포맷팅
const dt = DateTime.now().setLocale('ko');
console.log(dt.toLocaleString(DateTime.DATE_FULL));
// 출력 예: 2026년 2월 3일
const inNewYork = dt.setZone('America/New_York');
console.log(inNewYork.toString());
대안 3: 함수형 프로그래밍의 정수 date-fns
date-fns는 “자바스크립트의 lodash” 같은 느낌의 날짜 라이브러리입니다. 클래스나 인스턴스가 아닌 순수 함수들로 이루어져 있습니다.
주요 특징
- 최고의 Tree-shaking: 필요한 함수만
import해서 쓰기 때문에 번들 사이즈를 최소화할 수 있습니다. - Native Date 활용: 자체적인 객체 타입을 만들지 않고 자바스크립트 내장
Date객체를 그대로 사용합니다. - 함수형 패러다임: 각 함수가 독립적이어서 테스트와 재사용이 용이합니다.
import { format, addDays } from 'date-fns';
import { ko } from 'date-fns/locale';
const today = new Date();
const tomorrow = addDays(today, 1);
// 내장 Date 객체를 그대로 사용하여 포맷팅
const formatted = format(tomorrow, 'yyyy-MM-dd (EEEE)', { locale: ko });
console.log(formatted); // 2026-02-04 (수요일)
한눈에 비교하는 라이브러리 선택 가이드
| 구분 | Day.js | Luxon | date-fns |
|---|---|---|---|
| 핵심 컨셉 | Moment와 유사, 초경량 | Moment의 현대적 계승자 | 함수형 도구 모음 |
| 번들 사이즈 | 매우 작음 (플러그인 방식) | 중간 | 매우 작음 (Tree-shaking 최적화) |
| Immutability | 지원 | 지원 | 지원 (Native Date 사용) |
| 타임존 처리 | 플러그인 필요 | 매우 강력 (내장) | 별도 패키지 필요 |
| 학습 곡선 | 매우 낮음 | 보통 | 낮음 |
💡 개발자의 팁: 마이그레이션 시 주의사항
기존에 Moment.js를 사용하던 거대한 프로젝트를 한 번에 옮기려고 하지 마세요.
- 신규 컴포넌트나 모듈부터 Day.js나 date-fns를 적용하세요.
eslint-plugin-you-dont-need-momentjs를 사용하여 점진적으로 교체하는 것을 추천합니다.- 특히
Moment객체가 전역적으로 공유되고 있다면, Immutability 차이로 인한 로직 변화를 반드시 확인해야 합니다.
FAQ
1. Moment.js를 계속 사용하면 안 되나요?
사용할 수는 있지만 권장하지 않습니다. 보안 업데이트와 메이저 버그 수정은 이루어지지만, 성능이 떨어지고 패키지 크기가 큽니다. 특히 최신 프레임워크(React, Vue, Astro 등) 환경에서는 성능 저하의 주범이 될 수 있습니다.
2. 타임존 처리가 복잡한 글로벌 서비스라면 무엇이 좋을까요?
Luxon을 추천합니다. 브라우저의 내장 Intl을 가장 잘 활용하며, 타임존 데이터 처리가 매우 정교하게 설계되어 있습니다.
3. 가장 가벼운 라이브러리는 무엇인가요?
기능을 얼마나 쓰느냐에 따라 다르지만, 단순히 날짜 포맷팅과 가벼운 연산만 한다면 Day.js가 가장 가볍습니다. 만약 극단적인 Tree-shaking이 필요하다면 date-fns가 유리합니다.
마치며: 어떤 라이브러리를 선택해야 할까?
라이브러리 선택에 정답은 없지만, 프로젝트의 성격에 따라 다음과 같은 가이드를 드릴 수 있습니다.
- Moment.js 코드가 너무 많아 빠르게 교체하고 싶다 → Day.js
- 함수형 프로그래밍을 선호하고 필요한 함수만 쓰고 싶다 → date-fns
- 복잡한 타임존 연산과 국제화 처리가 핵심이다 → Luxon
지금 바로 여러분의 package.json에서 moment를 지우고, 현대적인 대안을 적용해 보시는 건 어떨까요?