Quick Comparison
path.join()은 세그먼트를 이어 붙이고, path.resolve()는 현재 작업 디렉터리를 기준으로 절대 경로를 계산합니다. ESM의 현재 모듈 기준 파일은 URL로 만들고, fs에는 URL을 직접 넘기거나 문자열 path API가 필요할 때만 변환합니다.
import path from "node:path";
import { readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
const relative = path.join("src", "utils", "helper.js");
const absolute = path.resolve("src", "utils", "helper.js");
const fileUrl = new URL("./data.json", import.meta.url);
const text = await readFile(fileUrl, "utf8");
const filePath = fileURLToPath(fileUrl); // 문자열 path가 필요한 API에서만
console.log(relative, absolute, filePath, text);경로와 URL
먼저 구분해 둘 기본형은 아래입니다.
- 세그먼트 조립:
path.join(...) - 절대 위치 계산:
path.resolve(...) - URL -> 경로:
fileURLToPath(...) - 경로 -> URL:
pathToFileURL(...) - ESM 기준점:
import.meta.url
join과 resolve
join은 경로 조각을 붙이는 쪽이고, resolve는 최종적으로 절대 경로를 만들고 싶을 때 더 자주 씁니다.
path.join("src", "utils", "helper.js");
path.resolve("src", "utils", "helper.js");실전에서는 파일 시스템 API에 넘길 경로라면 resolve 쪽이 더 안전한 경우가 많습니다. 반면 URL 경로나 내부 상대 세그먼트 조립은 join이 더 자연스러울 수 있습니다.
path.join("/app", "/tmp", "a.txt"); // 세그먼트 연결
path.resolve("/app", "/tmp", "a.txt"); // 절대 경로 기준 재계산즉 join은 "붙인다", resolve는 "최종 위치를 계산한다"로 읽는 편이 빠릅니다.
cwd 기준인지 현재 파일 기준인지 먼저 나눈다
실무에서 경로 버그는 join과 resolve 차이보다도 "이 경로가 어디를 기준으로 계산되느냐"에서 더 자주 납니다.
사용자 실행 위치 기준이면 process.cwd(), 현재 모듈 기준이면 import.meta.url 또는 __dirname 패턴을 먼저 떠올리는 편이 맞습니다.
ESM 기준점
ESM에서는 import.meta.url부터 시작한다
ESM에서 많이 다시 찾는 패턴은 이겁니다.
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
const __dirname = dirname(fileURLToPath(import.meta.url));
const filePath = join(__dirname, "data.json");핵심은 import.meta.url이 파일 경로가 아니라 URL이라는 점입니다. 대부분의 node:fs API는 file: URL 객체를 직접 받을 수 있습니다.
즉:
- path 함수에 바로 넣지 않는다
fs에는new URL(...)을 직접 넘길 수 있다- 문자열 path가 필요한 API에서만
fileURLToPath()로 변환한다
변환 경계
경로와 URL은 서로 바꿔야 할 때가 있다
node:fsAPI 대부분은 path 또는file:URL을 받음- Worker, 동적 import, 일부 Web API 흐름은 URL이 더 자연스러움
그래서 fileURLToPath()와 pathToFileURL()은 "한 번쯤 필요한 희귀 함수"가 아니라 ESM 환경에서 계속 다시 찾는 변환 카드입니다.
const workerUrl = pathToFileURL("/app/worker.js");언제 무엇을 기준으로 쓸까
체크포인트
- 상대 세그먼트 조립:
join - 절대 경로 필요:
resolve - ESM 파일 위치 기준:
new URL("./file", import.meta.url) - path API 경계에서만
fileURLToPath()로 변환 cwd기준인지 현재 파일 기준인지 먼저 확인
잘못된 예시는 보통 이쪽입니다.
const filePath = path.join(import.meta.url, "data.json");import.meta.url은 경로가 아니라 URL이므로 바로 path.join()에 넣으면 안 됩니다.
주의할 점
경로와 URL은 비슷해 보여도 타입과 의미가 다릅니다. 문자열로 대충 이어 붙이면 로컬에서는 우연히 돌아가도, 공백·인코딩·운영체제 차이에서 바로 깨지기 쉽습니다. 특히 ESM 파일 기준 경로는 URL로 만든 뒤, 문자열 path API가 요구할 때만 변환합니다.
참고 링크
2 sources