URLs, Piece by Piece
Table of Contents
- A URL Is an Address with Parts
- The Scheme
- The Host
- The Port
- The Path
- The Query String
- The Fragment
- Spaces and Special Characters
- Absolute and Relative Links
- Try It Yourself
1. A URL Is an Address with Parts
A URL (Uniform Resource Locator) tells a client where a resource is and how to get it. It looks like one long string, but it's really several pieces glued together with punctuation:
https://shop.example.com:443/products/shoes?color=red&size=42#reviews
└─┬─┘ └──────┬───────┘ └┬┘└──────┬──────┘ └───────┬───────┘ └──┬──┘
scheme host port path query fragment
Every piece answers a different question:
| Part | Question it answers | Example |
|---|---|---|
| Scheme | How do I talk to the server? | https |
| Host | Which server? | shop.example.com |
| Port | Which program on that server? | 443 |
| Path | Which resource on that server? | /products/shoes |
| Query | Any extra options? | color=red&size=42 |
| Fragment | Which part of the page? | reviews |
Most URLs you see leave some of these out. Let's go through them one at a time.
2. The Scheme
The scheme comes first, followed by ://. It tells the client which
protocol — which set of rules — to use.
https— HTTP, encrypted. Almost every site today.http— HTTP, not encrypted. Fine forlocalhostwhile you develop; a bad idea anywhere else (chapter 4 explains why).
You'll see other schemes too: mailto: opens your email app (this
site's contact page uses one), tel: dials a phone number, file://
opens a file on your own computer, and ws:///wss:// are for
WebSockets.
When you type example.com without a scheme, the browser fills one in
for you. Modern browsers try https:// first.
3. The Host
The host says which server to contact. It's usually a domain name, read from right to left, from most general to most specific:
shop . example . com
│ │ └── top-level domain (TLD)
│ └────────── the domain someone registered
└────────────────── a subdomain they created
- Top-level domain (TLD):
.com,.org,.dev, or a country code like.khfor Cambodia. - Domain:
example.com— the name someone rents from a registrar, usually yearly. - Subdomain:
shop,www,api,docs— anything to the left. The owner ofexample.comcan create as many as they like, for free.
Your GitHub Pages address, dara-sok.github.io, is a subdomain:
GitHub owns github.io and gives every user their own subdomain.
The host can also be an IP address directly, like
http://192.168.1.1 for many home routers, or the special name
localhost, which always means "this computer". Chapter 3 shows how
names turn into numbers.
Domain names are not case-sensitive: EXAMPLE.com and example.com
are the same.
4. The Port
One server computer can run many server programs at once — a website, a database, an SSH server. The port is a number from 0 to 65535 that says which program on that computer you want. Think of the IP address as a building and the port as the apartment number.
You almost never see ports in URLs, because each scheme has a default:
| Scheme | Default port |
|---|---|
http | 80 |
https | 443 |
So https://example.com really means https://example.com:443. You only
write the port when it's not the default — which is why you've seen
URLs like http://localhost:3000 in the NestJS and Docker tutorials.
Development servers use ports like 3000, 5173, or 8080 so they don't
clash with each other.
5. The Path
The path starts at the first / after the host and says which
resource you want on that server:
https://dara-sok.github.io/my-site/about.html
└────────┬────────┘
path
On a simple static site like yours, the path maps straight onto
folders and files, exactly like the file paths from Command Line
Basics: /my-site/about.html is the file about.html inside the
my-site folder on GitHub's server.
When the path ends in a folder — /my-site/ — the server looks for a
default file, almost always index.html. That's why your home page
had that name.
On a web app, the path doesn't have to match any file. A NestJS server
might answer /users/42 by looking up user 42 in a database. The path
is just a string; it's up to the server what it means.
Unlike the host, paths are usually case-sensitive: /About.html
and /about.html can be different files.
6. The Query String
After a ? comes the query string: extra options, as key=value
pairs separated by &.
https://www.google.com/search?q=phnom+penh&hl=km
└─────┬────────┘
q = "phnom penh", hl = "km"
Queries are used for things like search terms, filters, sorting, and
page numbers: ?page=2, ?sort=price, ?color=red&size=42. The server
(or JavaScript in the page) reads them and changes what it returns.
Two warnings:
- Query strings are visible: in the address bar, in browser history, and in server logs. Never put passwords or secrets in a URL.
- The order usually doesn't matter to the server, but to a cache
(chapter 9)
?a=1&b=2and?b=2&a=1can look like different URLs.
7. The Fragment
The fragment is everything after #. It points to a part of the
page, not a different page:
https://example.com/guide#installation
The browser scrolls to the element with id="installation". The
table of contents at the top of this chapter works exactly this way —
click one and watch the address bar.
The important detail: the fragment is never sent to the server. The
browser keeps it to itself. The server receives a request for /guide
and nothing more; the scrolling happens entirely in the browser.
8. Spaces and Special Characters
URLs can only contain a limited set of characters. Spaces, Khmer
letters, and symbols like & or ? (when they're data, not
punctuation) must be percent-encoded: replaced with % followed by
the character's byte value in hex — the same bytes and hex numbers from
the Bits and Bytes chapter of How Computers Work.
| Character | Encoded |
|---|---|
| space | %20 (or + in a query string) |
& | %26 |
/ | %2F |
ក (Khmer letter) | %E1%9E%80 |
That last one is three bytes because Khmer letters take three bytes in UTF-8. Browsers usually show you the readable version in the address bar, but send the encoded one. Copy a URL with a space or Khmer text in it and paste it into a text editor to see the real thing.
9. Absolute and Relative Links
In HTML, a link can be written two ways.
An absolute URL includes everything:
<a href="https://dara-sok.github.io/my-site/about.html">About</a>
A relative URL leaves parts out, and the browser fills them in from
the page you're on. Suppose you're on
https://dara-sok.github.io/my-site/index.html:
| You write | The browser goes to |
|---|---|
about.html | https://dara-sok.github.io/my-site/about.html |
./about.html | same as above — . means "this folder" |
../other/ | https://dara-sok.github.io/other/ — .. means "up one folder" |
/about.html | https://dara-sok.github.io/about.html — starts from the root of the host |
#contact | the same page, scrolled to id="contact" |
The . and .. work exactly like cd in the terminal. The one that
trips people up is the leading /: on GitHub Pages, your site lives in
/my-site/, so /about.html skips right past it and gives you a 404.
That's why the Git series used plain relative links like about.html.
10. Try It Yourself
- Label the parts. Write out the scheme, host, port, path, query,
and fragment for each of these. Some parts are missing — say which,
and what the default would be.
https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=42http://localhost:3000/api/users/7https://dara-sok.github.io/my-site/#contact
- Watch the fragment stay home. Open your site (or any page with
headings) with DevTools → Network open. Click a table-of-contents
link or add
#somethingto the address. No new request appears — the browser just scrolls. - See encoding. Search Google for something in Khmer. Copy the
address bar and paste it into a text editor. Find the
%E1%9E…bytes. - Change the query. On a shopping or search site, change a value
in the query string by hand —
page=1topage=2, for example — and press Enter. You just did what the site's "next" button does.
Next, we'll follow the host part of the URL and find out how the browser turns a name into an actual computer to talk to.
Buy Me a Coffee
Found this tutorial helpful? Consider buying me a coffee to support more free content!