url.join
v0.1.0 latestJoin URL path segments with path-join semantics and optional query parameter merging per RFC 3986.
Join URL path segments with path-join semantics and optional query parameter merging per RFC 3986.
Signature
function join(base: string, ...parts: (string | Record<string, unknown>)[]): string
Problem
Building URLs from base paths and segments requires careful slash deduplication (base/ + /path → base/path, not base//path). Appending query parameters requires manual encoding and ? vs & selection. These patterns are repeated across every HTTP client call.
How It Works
Handles double-slash deduplication at join boundaries. The last Record argument is merged as query parameters using RFC 3986 encoding. null/undefined query values are skipped.
Boundaries
- Uses path-join semantics, not RFC 3986 relative-reference resolution.
- Record argument must be the last argument; placing it elsewhere throws TypeError.
- Does not normalize the resulting URL (no percent-decoding, no WHATWG URL parsing).
- Throws TypeError for non-string base.
Replaces
Common boilerplate this function replaces:
base + '/' + path + '?' + new URLSearchParams(query).toString()
Examples
url.join("https://api.example.com/", "/v1/", "users"); // "https://api.example.com/v1/users"
url.join("https://api.example.com", "search", { q: "hello", page: "1" }); // "https://api.example.com/search?q=hello&page=1"
url.join("/base/", "/path/"); // "/base/path/"
url.join("https://example.com/api", { page: "1" }); // "https://example.com/api?page=1"
Standards
Caveats
- This is path-join, not RFC 3986 relative reference resolution. For spec-compliant resolution, use the URL constructor.
- Query parameters are encoded using RFC 3986 with skipNull: true.
FAQ
How to join URL path segments in JavaScript?
url.join('https://api.com/', '/v1/', 'users') returns 'https://api.com/v1/users'. Handles slash deduplication automatically.
How to append query parameters to a URL?
Pass a Record as the last argument: url.join('https://api.com', 'search', { q: 'hello' }) returns 'https://api.com/search?q=hello'.
Does url.join handle double slashes?
Yes. url.join('https://api.com/', '/path') deduplicates to 'https://api.com/path'.
Can I use url.join for relative paths?
Yes. url.join('/base/', '/path/') returns '/base/path/'. It uses path-join semantics.
How are null query values handled?
null and undefined values are skipped. url.join('/api', { a: '1', b: null }) produces '/api?a=1'.