URL Anatomy Explained: Every Part of a Link

🔗 ~15K searches/mo (est.)💰 CPC: $0.5–1.5⏱️ 6 min read

You paste URLs every day, but a URL is really seven tiny fields in a trench coat: scheme, userinfo, host, port, path, query, fragment. Knowing which is which turns debugging from superstition into procedure — you'll know why the port disappeared, why %20 shows up in your analytics, and why that # section never shows up in server logs.

Dissect a URL right now

Paste any link — get every component plus decoded query parameters, editable, with a rebuilt URL.

Open the URL Parser

The seven parts, left to right

https://user:[email protected]:8443/products/search?q=bag&max=150#results

PartExampleWhat it does
SchemehttpsPicks the protocol — and its default port (443 for https, 80 for http)
Userinfouser:pass@Legacy credentials-in-URL. Rare, still valid, frowned upon
Hoststore.example.comWhere to connect — DNS name or IP
Port:8443Overrides the scheme's default port
Path/products/searchThe resource on that server; starts with /
Query?q=bag&max=150&-separated key=value pairs; the only place ? and & are structural
Fragment#resultsIn-page anchor; browser-only, never sent to the server

Why the port sometimes vanishes

Type https://example.com:443/ into the URL parser and the port field comes back empty. The WHATWG URL parser normalizes away any port that equals the scheme's default — 443 for https, 80 for http, 21 for ftp — because https://example.com:443/ and https://example.com/ are the same resource. A port like :8443 or :3000 (dev servers love 3000) is non-default, so it survives parsing and shows up everywhere: in the origin, in CORS checks, in your cookie domain matching. That's also why localhost:3000 and localhost can't share login cookies by default — different origins.

Percent-encoding: the escaping system

URLs were born ASCII-only, so everything else gets escaped: a percent sign followed by two hex digits per byte. The ones you'll actually meet:

The classic bug: hand-building a query string with raw values. A value like P&G silently splits into two params. The fix is one line — encodeURIComponent(value) — and it's why the URL parser tool rebuilds URLs for you instead of trusting string concatenation.

Query strings: more than key-value

Everything between ? and # is the query string. Rules worth internalizing:

The fragment: the part the server never sees

Everything after # stays in the browser. The browser scrolls to the matching element ID (or lets JavaScript read it via location.hash), strips it from the request, and logs nothing. Consequences you can verify: adding #anything to a URL never triggers a reload or a new server hit, analytics tools deliberately put campaign IDs after ? rather than # when they want the server (or a redirect) to see them, and single-page apps route with fragments precisely because fragment changes are free.

URI versus URL, in one paragraph

A URI identifies; a URL identifies and locates. https://example.com/x is both — it names the resource and says how to fetch it. mailto:[email protected] and urn:isbn:0451450523 are URIs that aren't URLs: they identify, but there's no fetch procedure. Web people say "URL" for everything because in browser-land, everything worth parsing is one; the WHATWG spec governs that parser, and it's the exact code this site's URL parser calls.

Frequently Asked Questions

What are the 7 parts of a URL?

Scheme, userinfo, host, port, path, query string, and fragment. In https://user:[email protected]:8443/a/b?x=1#top those are https, user:pass@, example.com, 8443, /a/b, ?x=1, and #top. Only scheme, host, and path are required in practice; the rest appear when used.

What is the difference between a URL's host and hostname?

Hostname is the domain alone (example.com). Host is hostname plus port when one is written (example.com:8443). HTTP's Host header technically sends the host — domain and explicit port both — which is how one server can serve multiple sites on different ports.

Why do some characters become %20 in a URL?

URLs allow a limited ASCII set, so everything else gets percent-encoded: a % followed by the character's hex bytes. A space becomes %20, a literal % becomes %25 (which is why 10% off encodes as 10%25%20off), and non-ASCII characters encode per UTF-8 byte — é becomes %C3%A9 because é is two bytes.

Does the part after # get sent to the server?

Never. The fragment is client-side only: the browser keeps it, jumps to the matching element, and strips it before the HTTP request. That's why server logs never contain fragments and why single-page apps use them for navigation — changing #anything never triggers a reload.

Related Tools