Search across all documentation pages
node:path builds filesystem paths; node:url parses and resolves HTTP and file:// URLs - conflating them causes broken imports, bad redirects, and SSRF bugs.
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const dir = path.dirname(fileURLToPath(import.meta.url));
const config = path.join(dir, 'config.json');import { URL } from 'node:url';
const u = new URL('https://api.example.com/v1/users?page=2');
u.searchParams.set('limit', '50');When to reach for this:
dist/ outputimport.meta.url to absolute filesystem pathimport path from 'node:path';
import { fileURLToPath, URL } from 'node:url';
// ESM __dirname equivalent
const root = path.dirname(fileURLToPath(import.meta.url));
const dataFile = path.resolve(root, '..'
What this demonstrates:
path.resolve and join prevent manual slash bugsURL constructor resolves relative paths against base URLsearchParams encodes query strings correctlyprotocol and hostname before fetchwin32 vs posix internals) - path.join picks separators.URL.| Task | Module |
|---|---|
| Join config dir | path.join |
| Parse query string on HTTP URL | URL |
| S3 object key | path.posix.join |
| Normalize redirect URL | new URL(input, base) |
import path from 'node:path';
export function safeJoin(base: string, userSegment: string): string {
const resolved = path.resolve(base, userSegment);
if (!resolved.startsWith
URL for HTTP, path for disk.path.join(base, userInput) - ../etc/passwd. Fix: resolve and verify prefix under base.url.pathname is filesystem path on Windows - leading slash POSIX-like. Fix: fileURLToPath for file: URLs only.new URL(relative, base).new URL handles bracketed host http://[::1]:8080.| Alternative | Use When | Don't Use When |
|---|---|---|
URL.canParse | Quick validity check | Need filesystem join |
path-to-regexp | Express route patterns | General URL parsing |
| Raw template strings | Never for user input | - |
| WHATWG URL in fetch | Client outbound | Local file paths |
path.dirname(fileURLToPath(import.meta.url)).
resolve absolutizes from right; join only concatenates - use resolve for user-relative paths with guard.
new URL('http://x?' + qs) or url.searchParams - not manual split for encoded values.
fileURLToPath converts to C:\... correctly with three-slash form.
Validate hostname allowlist before server-side fetch - see SSRF Guards.
Yes for S3 keys and URL-like routes stored as posix paths.
Jest/Vitest set import meta - paths still resolve relative to test module.
searchParams.set encodes once - do not pre-encode values.
Deprecated - use WHATWG URL constructor.
new URL('/api', 'https://x.com/v1/') - base path matters - test carefully.
Framework handles path params - use URL for outbound calls only.
Container paths are Linux - use posix inside container regardless of dev OS.
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.