TS-63: URL Design
🚧 DRAFT
A URL is an address that identifies a resource on the web. Well-designed URLs are readable, predictable, durable, and shareable. They are part of the user interface, because they appear in browser address bars, links, bookmarks, printed material, and API client code. Poor URL design degrades usability, maintainability, and search ranking.
This technical standard covers the design of URLs for all kinds of HTTP services, including websites, web applications, and HTTP APIs. It is concerned with the structure and semantics of URLs themselves, not with the resources they identify or the protocols used to transfer them.
For general user interface design principles, see TS-15. For web GUI implementation, see TS-18. For search engine optimization, see TS-19. For HTTP API resource modeling and versioning, see TS-21.
Anatomy of a URL
A URL is composed of several parts, each with a distinct role. The RFC 3986 grammar defines them. The WHATWG URL Standard defines how browsers parse them in practice.
https://example.com:8443/v1/users/42?sort=name#profile
\___/ \___________/\__/\_______/\_/ \_______/\______/
| | | | | | |
scheme host port path path query fragment
segments- Scheme —
httporhttps. HTTPS is REQUIRED for any production service. URLs in documentation and links SHOULD use thehttpsscheme. - Host. The domain name (or IP address) that identifies the server.
- Port. Omitted when it is the default for the scheme (80 for HTTP, 443 for HTTPS). Non-default ports SHOULD be avoided in production URLs.
- Path. A slash-delimited sequence of segments that locates a resource within the service. Path design is the subject of Path design.
- Query string. Key-value pairs that parameterize the request. See Query strings.
- Fragment. A client-side anchor that identifies a secondary resource or position within the primary resource. See Fragments.
Case sensitivity
The scheme and host components of a URL are case-insensitive and SHOULD be written in lowercase. The path, query string, and fragment are case-sensitive (except for the percent-encoding of reserved characters, which is case- insensitive). To avoid ambiguity, path segments and query parameter names SHOULD be treated as case-sensitive and SHOULD be written in lowercase.
Path design
The path is the most consequential part of a URL. It identifies a resource and is the part most often read, shared, and remembered.
Use readable, meaningful path segments
Path segments SHOULD be human-readable words that describe the resource they identify. Opaque identifiers, internal codes, and implementation details SHOULD NOT appear in paths intended for human consumption.
# Good: https://example.com/blog/2023/url-design # Poor: https://example.com/p/12345?c=789
Use lowercase letters, digits, and hyphens
Path segments SHOULD use lowercase letters, digits, and hyphens only. Words within a segment SHOULD be separated with hyphens (kebab-case), not underscores or camelCase.
# Good: https://example.com/charge-points/42 https://example.com/blog/how-to-design-urls # Poor: https://example.com/ChargePoints/42 https://example.com/charge_points/42 https://example.com/chargePoints/42
Hyphens are preferred because they are the standard word separator in URLs and are treated as word boundaries by search engines and screen readers.
Keep paths shallow
Path depth SHOULD be kept to the minimum necessary to identify a resource. Deeply nested paths are harder to read, harder to type, and harder to restructure. As a rule of thumb, paths SHOULD NOT exceed three or four segments for websites, or five or six for HTTP APIs that model resource hierarchies.
# Good: https://example.com/blog/url-design # Poor: https://example.com/site/content/blog/posts/2023/01/url-design
Trailing slashes
A trailing slash indicates that the path identifies a collection or a directory- like resource. A URL without a trailing slash identifies a specific resource.
Services SHOULD be consistent in their use of trailing slashes. It is RECOMMENDED that canonical URLs omit the trailing slash for individual resources and use it only for collections. A service SHOULD accept requests with or without a trailing slash, but SHOULD NOT respond with a redirect to the canonical version — redirects add a round trip and complicate caching.
File extensions
File extensions (.html, .php, .aspx) SHOULD NOT appear in URLs. They expose implementation details and make it
harder to change the underlying technology. The content type is conveyed by the Content-Type header, not by the URL.
Exceptions MAY be made where the extension carries semantic meaning for the resource, such as a downloadable file
(report.pdf) or a format variant (data.json, data.xml).
Identifiers in paths
When a path includes a resource identifier, the identifier SHOULD be the final segment. Opaque, sequential identifiers
(eg. 42) MAY be used, but human-readable slugs are RECOMMENDED where the identifier is visible to end users.
# Good: https://example.com/blog/url-design https://example.com/users/42 # Poor: https://example.com/42/url-design
For HTTP APIs, see TS-21 for guidance on resource identifiers, collections, and sub-resource hierarchies.
Query strings
The query string carries parameters that modify or filter the request without identifying a different resource. It is the appropriate place for sorting, filtering, pagination, and other request options.
Use query strings for parameters, not for identity
The path identifies the resource; the query string parameterizes the request. Values that change which resource is identified belong in the path. Values that change how the resource is represented or selected belong in the query string.
# Good: https://example.com/articles?sort=date&order=desc https://example.com/search?q=url+design # Poor: https://example.com/articles?category=web
The second example is poor because category identifies a different collection of articles; it belongs in the path
(https://example.com/categories/web/articles).
Naming query parameters
Query parameter names SHOULD be short, lowercase, and descriptive. Multi-word names SHOULD use hyphens or underscores consistently within a single service; hyphens are RECOMMENDED for consistency with path segments.
# Good: https://example.com/articles?sort-by=date # Poor: https://example.com/articles?SortBy=date https://example.com/articles?sortBy=date
Boolean parameters
Boolean query parameters MAY be specified as key-only flags (?verbose) or as key-value pairs (?verbose=true). A
service SHOULD pick one convention and apply it consistently. Key-value pairs are RECOMMENDED for HTTP APIs, as they are
easier to document and to compose programmatically.
Encoding
Reserved characters in query strings MUST be percent-encoded. Spaces SHOULD be encoded as + (in
application/x-www-form-urlencoded contexts) or %20 (in all other contexts); a service SHOULD accept both.
Fragments
The fragment identifies a secondary resource — typically a section within an HTML document — and is not sent to the server. It is resolved client-side by the user agent.
Use fragments for in-page navigation
In HTML documents, fragments SHOULD identify sections by their heading text or by an explicit id attribute. Fragments
that match heading text are auto-generated by many tools and are stable across content edits; fragments based on
auto-generated numeric IDs are not.
https://example.com/blog/url-design#path-design
Fragments and APIs
Fragments are not part of the request that reaches the server and have no defined semantics for non-HTML resources. HTTP APIs SHOULD NOT rely on fragments to convey request parameters.
Permanence
A URL is a contract. Once a URL is published — linked from another page, printed in a book, bookmarked by a user, or indexed by a search engine — it SHOULD continue to resolve to the intended resource for as long as the resource exists. This principle was articulated by Tim Berners-Lee in Cool URIs don’t change.
Design for permanence from the start
The surest way to keep URLs stable is to design them so that they never need to change. Avoid embedding implementation details, technology choices, or transient organizational structures in URLs.
# Good: https://example.com/blog/url-design # Poor: https://example.com/wordpress/2023/01/url-design.php
The poor example exposes the CMS (wordpress), the publication date (which may be wrong or revised), and the server
technology (.php). Each is a detail that could change and break the URL.
Redirects for moved resources
When a resource moves and its URL must change, the old URL SHOULD redirect to the new one with an HTTP 301 Moved
Permanently response. Redirects SHOULD be maintained indefinitely, since links to the old URL may persist anywhere on
the Web. A 410 Gone response MAY be used for resources that have been permanently removed and have no replacement.
Versioning and change
For HTTP APIs, breaking changes are managed through versioning in the URL path (see TS-21). For websites and web applications, content changes SHOULD NOT require a URL change; the URL identifies the resource, not a particular version of its representation.
Avoid dates in URLs unless they are part of the identity
Including a publication date in a URL (/blog/2023/01/url-design) makes the URL brittle: if the date is corrected, the
URL breaks. Dates SHOULD be included only when the date is an intrinsic part of the resource’s identity — for example, a
daily archive (/news/2023-01-15) or a recurring event (/events/2023/agenda).
References
- Berners-Lee, T. Cool URIs Don’t Change.
- Google Search Central. URL Structure.
- IETF. RFC 3986: Uniform Resource Identifier (URI): Generic Syntax.
- Nielsen, J (2023). Examples of Great URLs.
- WHATWG. URL Standard.