A URI, or Uniform Resource Identifier, is a compact string with a standardized syntax that identifies a resource, whether a web page, a mailbox, a file, a book or an abstract concept. Among Internet protocols, it is the common naming format shared by HTTP, HTTPS, FTP, email, XML namespaces and many application protocols, and its generic grammar is defined in RFC 3986.
A URI identifies a resource; it does not by itself promise that the resource can be retrieved. The more familiar URL is a kind of URI that also tells a client how to locate and fetch the resource, while a URN names something persistently without saying where it lives.
The generic syntax of a URI
Every URI follows the same five-component grammar: scheme:[//authority]path[?query][#fragment]. Only the scheme and the path are mandatory, although the path may be empty. Taking https://user@shop.example.com:8443/items/42?color=red#reviews as an example, each part has a defined role.
| Component | Example | Role |
|---|---|---|
| Scheme | https | Names the specification that governs the rest |
| Authority | user@shop.example.com:8443 | Userinfo, host and optional port |
| Path | /items/42 | Hierarchical location within the authority |
| Query | color=red | Non-hierarchical parameters |
| Fragment | reviews | Secondary resource, handled by the client |
The scheme is case-insensitive and determines how the remaining characters are interpreted. Schemes are registered with IANA; common ones include http, https, mailto, ftp, file, tel, data and urn. The fragment is never sent to the server in HTTP: the browser strips it and uses it locally, for example to scroll to an anchor.
The authority can contain a registered name, an IPv4 address or an IPv6 literal in square brackets, such as [2001:db8::1]. When the port is omitted, the scheme’s default port applies, which is 80 for http and 443 for https.
URI, URL and URN compared
The three acronyms describe overlapping categories, not competing technologies. URI is the umbrella term. A URL is a URI whose main purpose is locating a resource through a network access mechanism, and a URN is a URI in the urn scheme designed for persistent, location-independent names.
| Identifier | Purpose | Example | Retrievable by itself |
|---|---|---|---|
| URI | Identify any resource | Any of the forms below | Depends on the scheme |
| URL | Identify and locate | https://example.com/a | Yes, with the right protocol |
| URN | Name persistently | urn:isbn:9780000000002 | No, needs a resolver |
| IRI | URI with Unicode characters | https://example.com/café | After conversion to a URI |
Modern specifications, including the WHATWG URL Standard used by browsers, tend to use “URL” for everything that browsers parse. In formal protocol documents, however, URI remains the precise term, and the distinction matters when an identifier such as an XML namespace is never meant to be dereferenced.
Percent-encoding and allowed characters
A URI may contain only a limited set of ASCII characters. Letters, digits and the four characters -, ., _ and ~ are unreserved and never need encoding. Reserved characters such as /, ?, #, & and = act as delimiters, so when they appear as data they must be percent-encoded: a percent sign followed by two hexadecimal digits for each byte.
Characters outside ASCII are first converted to UTF-8 bytes and then encoded byte by byte, so é becomes %C3%A9. A space becomes %20; the + convention for spaces belongs only to HTML form encoding in query strings, which is a frequent source of bugs.
| Character class | Examples | Treatment |
|---|---|---|
| Unreserved | A-Z a-z 0-9 - . _ ~ | Used as is, never encoded |
| General delimiters | : / ? # [ ] @ | Encode when used as data |
| Sub-delimiters | ! $ & ' ( ) * + , ; = | Meaning depends on the scheme |
| Everything else | Space, non-ASCII, % | Always percent-encode |
Relative references and normalization
Documents rarely repeat full URIs. A relative reference such as ../images/logo.png or ?page=2 is resolved against a base URI, normally the address of the current document. RFC 3986 defines an exact resolution algorithm, including the removal of . and .. segments, so that every conforming parser reaches the same absolute result.
Two URIs that look different may identify the same resource. Normalization reduces such variants to one form, which matters for caching, deduplication, security checks and search engine canonicalization.
- Case normalization: lowercase the scheme and host, and uppercase hexadecimal digits in percent-encodings.
- Percent-encoding normalization: decode any encoded unreserved character, so
%7Ebecomes~. - Path segment normalization: remove dot segments, turning
/a/./b/../cinto/a/c. - Scheme-based normalization: drop default ports and replace an empty path with
/for HTTP.
Paths and queries remain case-sensitive by default, so /Docs and /docs may be different resources. Only the server can say whether they are equivalent.
Security pitfalls in URI handling
Many vulnerabilities come from two components parsing the same URI differently. A validation filter and an HTTP client that disagree on where the host ends can be tricked by strings such as https://trusted.example@evil.example/, where the real host is evil.example and the first part is only userinfo.
| Mistake | Consequence | Safer practice |
|---|---|---|
| String matching on hosts | Open redirects and SSRF | Parse with one standard library, compare the host field |
| Double decoding | Path traversal past filters | Decode exactly once, then validate |
| Trusting the scheme blindly | Script execution via javascript: | Allowlist schemes such as https |
| Ignoring Unicode lookalikes | Phishing with spoofed hosts | Display hosts in punycode where risky |
The decisive recommendation is to parse once with a well-maintained library and make every decision on the parsed components, never on the raw string.
The idea in brief
A URI is a standard way of writing a name or address for something. Any program can read it and know which thing is meant. A web address is the most common example. The same format also works for email addresses, phone numbers and book numbers.
Think of it as a postal address with fixed parts. First comes the kind of delivery service. Then comes the building, and then the room. Because everyone follows the same layout, a browser, a mail program and a server all read the address the same way.
A practical scenario
A development team builds a search page whose links include user input, such as a query for rock & roll. Testers notice that searches containing an ampersand return wrong results: the server receives q=rock and treats roll as a separate, empty parameter.
The cause is that the ampersand was inserted into the query without percent-encoding, so it acted as a delimiter. The team switches to a URI builder that encodes each parameter value, producing ?q=rock%20%26%20roll, and adds tests with spaces, slashes and non-ASCII words such as café.
The fix also closes a related problem: a redirect parameter had been checked by searching the raw string for the company domain. The team now parses the URI and compares the host against an allowlist, which removes an open redirect found during the same review.