The path module provides utilities for working with file paths. Here's how to use it effectively.
Basic Path Operations#
1const path = require('path');
2
3// Join path segments
4const fullPath = path.join('users', 'alice', 'documents', 'file.txt');
5// 'users/alice/documents/file.txt' (Unix)
6// 'users\\alice\\documents\\file.txt' (Windows)
7
8// Resolve to absolute path
9const absolute = path.resolve('src', 'components', 'Button.tsx');
10// '/current/working/dir/src/components/Button.tsx'
11
12// Get directory name
13const dir = path.dirname('/users/alice/documents/file.txt');
14// '/users/alice/documents'
15
16// Get file name
17const file = path.basename('/users/alice/documents/file.txt');
18// 'file.txt'
19
20// Get file name without extension
21const name = path.basename('/users/alice/documents/file.txt', '.txt');
22// 'file'
23
24// Get file extension
25const ext = path.extname('/users/alice/documents/file.txt');
26// '.txt'Path Parsing and Formatting#
1const path = require('path');
2
3// Parse path into components
4const parsed = path.parse('/home/user/documents/report.pdf');
5// {
6// root: '/',
7// dir: '/home/user/documents',
8// base: 'report.pdf',
9// ext: '.pdf',
10// name: 'report'
11// }
12
13// Windows path
14const winParsed = path.win32.parse('C:\\Users\\Alice\\file.txt');
15// {
16// root: 'C:\\',
17// dir: 'C:\\Users\\Alice',
18// base: 'file.txt',
19// ext: '.txt',
20// name: 'file'
21// }
22
23// Format path from components
24const formatted = path.format({
25 root: '/',
26 dir: '/home/user',
27 base: 'file.txt',
28});
29// '/home/user/file.txt'
30
31// Partial format
32const partial = path.format({
33 dir: '/home/user',
34 name: 'document',
35 ext: '.pdf',
36});
37// '/home/user/document.pdf'Relative and Absolute Paths#
1const path = require('path');
2
3// Check if path is absolute
4path.isAbsolute('/foo/bar'); // true
5path.isAbsolute('./foo/bar'); // false
6path.isAbsolute('foo/bar'); // false
7
8// Windows
9path.win32.isAbsolute('C:\\foo'); // true
10path.win32.isAbsolute('\\foo'); // true
11path.win32.isAbsolute('foo'); // false
12
13// Get relative path between two paths
14const from = '/data/users/alice';
15const to = '/data/posts/123/content.md';
16const relative = path.relative(from, to);
17// '../../posts/123/content.md'
18
19// Resolve relative to specific directory
20const resolved = path.resolve('/home/user', './documents', '../downloads');
21// '/home/user/downloads'Path Normalization#
1const path = require('path');
2
3// Normalize path (resolve . and ..)
4path.normalize('/foo/bar//baz/asdf/quux/..');
5// '/foo/bar/baz/asdf'
6
7path.normalize('C:\\temp\\\\foo\\bar\\..\\');
8// 'C:\\temp\\foo\\'
9
10// Remove trailing slashes
11function removeTrailingSlash(p) {
12 return p.replace(/[\\/]+$/, '');
13}
14
15// Ensure trailing slash
16function ensureTrailingSlash(p) {
17 return p.endsWith(path.sep) ? p : p + path.sep;
18}
19
20// Clean path
21function cleanPath(p) {
22 return path.normalize(p).replace(/[\\/]+$/, '');
23}Cross-Platform Handling#
1const path = require('path');
2
3// Platform-specific separator
4console.log(path.sep);
5// '/' on Unix, '\\' on Windows
6
7// Platform-specific delimiter (for PATH)
8console.log(path.delimiter);
9// ':' on Unix, ';' on Windows
10
11// Force Unix paths
12const unixPath = path.posix.join('users', 'alice', 'file.txt');
13// 'users/alice/file.txt' (always)
14
15// Force Windows paths
16const winPath = path.win32.join('users', 'alice', 'file.txt');
17// 'users\\alice\\file.txt' (always)
18
19// Convert Windows paths to Unix
20function toUnixPath(p) {
21 return p.split(path.sep).join('/');
22}
23
24// Convert Unix paths to Windows
25function toWindowsPath(p) {
26 return p.split('/').join('\\');
27}
28
29// Platform-independent comparison
30function pathsEqual(p1, p2) {
31 return path.resolve(p1) === path.resolve(p2);
32}Common Patterns#
1const path = require('path');
2
3// Get project root
4const projectRoot = path.resolve(__dirname, '..');
5
6// Build file paths
7function getFilePath(filename) {
8 return path.join(projectRoot, 'data', filename);
9}
10
11// Change extension
12function changeExtension(file, newExt) {
13 const { dir, name } = path.parse(file);
14 return path.join(dir, `${name}${newExt}`);
15}
16
17changeExtension('/path/to/file.txt', '.md');
18// '/path/to/file.md'
19
20// Add suffix before extension
21function addSuffix(file, suffix) {
22 const { dir, name, ext } = path.parse(file);
23 return path.join(dir, `${name}${suffix}${ext}`);
24}
25
26addSuffix('/path/to/file.txt', '.min');
27// '/path/to/file.min.txt'
28
29// Get unique filename
30function uniqueFilename(file) {
31 const { dir, name, ext } = path.parse(file);
32 const timestamp = Date.now();
33 return path.join(dir, `${name}-${timestamp}${ext}`);
34}Working with __dirname and __filename#
1// CommonJS
2const path = require('path');
3
4console.log(__dirname); // Directory of current file
5console.log(__filename); // Full path of current file
6
7const configPath = path.join(__dirname, 'config.json');
8
9// ES Modules (no __dirname)
10import { fileURLToPath } from 'url';
11import { dirname, join } from 'path';
12
13const __filename = fileURLToPath(import.meta.url);
14const __dirname = dirname(__filename);
15
16const configPath = join(__dirname, 'config.json');
17
18// Helper for ES Modules
19function getDirname(importMetaUrl) {
20 return dirname(fileURLToPath(importMetaUrl));
21}
22
23const dir = getDirname(import.meta.url);Path Validation#
1const path = require('path');
2const fs = require('fs');
3
4// Check if path is within directory (prevent traversal)
5function isWithinDirectory(child, parent) {
6 const relative = path.relative(parent, child);
7 return relative && !relative.startsWith('..') && !path.isAbsolute(relative);
8}
9
10// Usage for security
11function safeReadFile(basePath, userPath) {
12 const fullPath = path.resolve(basePath, userPath);
13
14 if (!isWithinDirectory(fullPath, basePath)) {
15 throw new Error('Access denied: path traversal detected');
16 }
17
18 return fs.readFileSync(fullPath, 'utf-8');
19}
20
21// Validate filename
22function isValidFilename(filename) {
23 // No path separators
24 if (filename.includes('/') || filename.includes('\\')) {
25 return false;
26 }
27 // No special characters
28 const invalid = /[<>:"|?*\x00-\x1f]/;
29 return !invalid.test(filename);
30}
31
32// Sanitize filename
33function sanitizeFilename(filename) {
34 return filename
35 .replace(/[<>:"|?*\x00-\x1f]/g, '')
36 .replace(/[\\/]/g, '-')
37 .trim();
38}URL and Path Conversion#
1const path = require('path');
2const { URL, pathToFileURL, fileURLToPath } = require('url');
3
4// Path to file URL
5const fileUrl = pathToFileURL('/home/user/file.txt');
6// file:///home/user/file.txt
7
8// File URL to path
9const filePath = fileURLToPath('file:///home/user/file.txt');
10// '/home/user/file.txt'
11
12// URL path segment
13const url = new URL('https://example.com/path/to/file.txt');
14const urlPath = url.pathname;
15// '/path/to/file.txt'
16
17// Join URL paths
18function joinUrlPath(...segments) {
19 return segments
20 .map(s => s.replace(/^\/+|\/+$/g, ''))
21 .filter(Boolean)
22 .join('/');
23}
24
25joinUrlPath('/api/', '/users/', '/123');
26// 'api/users/123'Glob Pattern Helpers#
1const path = require('path');
2
3// Match file extension
4function matchesExtension(file, extensions) {
5 const ext = path.extname(file).toLowerCase();
6 return extensions.includes(ext);
7}
8
9// Get files matching pattern (basic)
10function getMatchingFiles(dir, pattern) {
11 const files = fs.readdirSync(dir);
12
13 if (pattern.startsWith('*.')) {
14 const ext = pattern.slice(1);
15 return files.filter(f => f.endsWith(ext));
16 }
17
18 return files.filter(f => f.includes(pattern.replace('*', '')));
19}
20
21// Build glob pattern
22function buildGlob(dir, extensions) {
23 const extPattern = extensions.length === 1
24 ? extensions[0]
25 : `{${extensions.join(',')}}`;
26
27 return path.join(dir, '**', `*${extPattern}`);
28}
29
30buildGlob('src', ['.ts', '.tsx']);
31// 'src/**/*.{ts,tsx}'Best Practices#
Cross-Platform:
✓ Always use path.join() for paths
✓ Use path.sep for separators
✓ Avoid hardcoded slashes
✓ Test on both platforms
Security:
✓ Validate paths from user input
✓ Use isWithinDirectory checks
✓ Sanitize filenames
✓ Resolve before validation
Patterns:
✓ Use path.resolve() for absolute paths
✓ Use path.parse() for components
✓ Store __dirname in ES Modules
✓ Normalize before comparing
Avoid:
✗ String concatenation for paths
✗ Assuming path separator
✗ Trusting user-provided paths
✗ Using relative paths without resolve
Conclusion#
The path module is essential for cross-platform file operations. Use path.join() and path.resolve() instead of string concatenation, validate user input to prevent path traversal, and use path.parse() for extracting components. Always consider cross-platform compatibility in your path handling code.