Skip to content
T
Tools.Town
Free Online Tools for Everyone
Developer Tools

The Anatomy of a URL: From Scheme to Fragment

A deep dive into every part of a URL — scheme, authority, host, port, path, query and fragment — plus punycode, default ports and how SPAs use the hash.

25 June 2026 4 min read By Tools.Town Team Fact Checked

Key Takeaways

  • Because 443 is the default port for https, the URL standard reports an empty port
  • Punycode is an ASCII encoding of internationalized domain names

A short history of URLs and URIs

When Tim Berners-Lee designed the web in 1991, he needed a single, universal way to point at any document anywhere. That idea became the URL. It was formalized in 1994 as RFC 1738, refined into the broader URI framework by RFC 3986 in 2005, and is now maintained as a living document by the WHATWG URL Standard — the version browsers actually implement today.

The terminology can be confusing. A URI (Uniform Resource Identifier) is the umbrella term for any identifier. A URL (Uniform Resource Locator) is a URI that also says where to find the thing and how to reach it. A URN (Uniform Resource Name) names something without locating it. In practice “URL” is what everyone means, and it is what the URL Parser is built to dissect.

The full skeleton

Every URL follows the same template, with each component marked off by a reserved delimiter:

scheme://userinfo@host:port/path?query#fragment

Not every part is always present — most URLs you click are just scheme://host/path — but the slots are always in this order, and the delimiters never move. Learn the delimiters and you can read any URL at a glance.

Scheme

The scheme is the protocol prefix: https, http, mailto, ftp, file, ws, wss. It ends at the first colon and tells the client how to handle the rest of the URL. Schemes are case-insensitive and normalized to lowercase. A handful of “special” schemes (http, https, ws, wss, ftp, file) carry extra rules: they require the // that introduces an authority, and they each have a default port.

Authority: userinfo, host, and port

The authority is introduced by // and answers “who serves this resource?”

Userinfo — an optional username:password@ prefix. Embedding credentials in a URL is now discouraged, and browsers strip or warn on them, but the syntax remains valid.

Host — the domain name or IP literal. IPv6 addresses are wrapped in brackets: https://[2001:db8::1]/. The host value includes a port if present; hostname never does.

Port — the TCP port. Crucially, ports have scheme defaults, so they are usually omitted.

Ports and their defaults

Every special scheme defines a default port:

SchemeDefault port
http80
https443
ws80
wss443
ftp21

When a URL uses its default port, the WHATWG URL parser reports the port as an empty string rather than the number — the default is implied. So https://example.com and https://example.com:443 are equivalent, and both report no explicit port. Only a non-default port like :8080 appears in the parsed output. This is intentional normalization, not a bug, and it surprises nearly everyone the first time.

Path and segments

The path begins at the first / after the host and identifies the specific resource. Splitting it on / yields ordered segments that map onto REST routes, file directories, and framework routers. A trailing slash produces a distinct path, and servers may treat /docs and /docs/ differently — a frequent cause of redirects and 404s. Dot-segments (. and ..) are resolved away during parsing, so /a/b/../c normalizes to /a/c.

Internationalized domain names and punycode

The global DNS only understands ASCII. So a domain like café.com or münchen.de cannot be sent over the wire as-is. The browser converts the Unicode hostname into punycode, an ASCII-compatible encoding prefixed with xn--. café.com becomes xn--caf-dma.com. You will see the human-readable form in the address bar but the punycode form in DNS lookups and TLS certificates. A good parser shows you the normalized ASCII host so you know exactly what will be resolved — and so you can spot lookalike “homograph” domains used in phishing.

Query parameters and their conventions

The query string starts at ? and ends at #. By convention it is a list of key=value pairs joined by &:

?page=2&sort=date&q=hello%20world

A few conventions worth knowing:

  • Repeated keys are valid and meaningful (?id=1&id=2). Use URLSearchParams.getAll() to retrieve every value.
  • Empty values (?flag=) and bare keys (?flag) are both legal and parse slightly differently across stacks.
  • Encoding is mandatory for spaces, &, =, and any non-ASCII character inside a value.
  • + for spaces is a form-encoding (application/x-www-form-urlencoded) convention, not part of the generic URL rules — URLSearchParams honors it, raw decoders may not.

The query string is opaque to the URL standard itself; structure is imposed by URLSearchParams, which is what the URL Parser uses to render a clean parameter table.

The fragment and how SPAs use it

The fragment is everything after #. It has two defining properties: it is never transmitted to the server, and it does not trigger a page reload when changed. Originally it just pointed at a named anchor so the browser could scroll to a heading.

Single-page applications repurposed it for client-side routing. Because changing #/dashboard to #/settings updates the URL without a server round-trip, early SPA routers built their entire navigation on the fragment (hash-based routing). Modern apps prefer the History APIhistory.pushState() and popstate — which lets them update the full path (/settings) without a reload while keeping clean, shareable URLs. The fragment is still widely used for in-page anchors, OAuth implicit-flow tokens, and deep-linking into client state. Either way, the server never sees it.

Putting it together

A URL only looks like a flat string. It is really seven labeled slots separated by fixed delimiters, each with its own rules — default ports, punycode hosts, encoded query values, and a fragment that never leaves the browser. Once you can name every part, debugging links, building API calls, and reasoning about routing all get dramatically easier.

For a hands-on, scenario-driven walkthrough with debugging tips, read How to Parse a URL. And whenever you want to see a real URL split into all of these components instantly and privately in your browser, reach for the URL Parser.

Advertisement

Try URL Parser — Free

Apply what you just learned with our free tool. No sign-up required.

Try URL Parser

Frequently Asked Questions

Why does the port look empty for an https URL?
Because 443 is the default port for https, the URL standard reports an empty port. The default is implied and only shown when a non-default port is used.
What is punycode?
Punycode is an ASCII encoding of internationalized domain names. café.com becomes xn--caf-dma.com so the global DNS, which only handles ASCII, can resolve it.

Was this guide helpful?

Your feedback helps us improve our content.

Get the best Developer Tools tips & guides in your inbox

Join 25,000+ users who get our weekly developer tools insights.