Cool URIs Don't Change

The philosophy and practice of permanent URLs

The Original Vision

In 1998, Tim Berners-Lee—inventor of the World Wide Web—wrote an essay titled "Cool URIs Don't Change." It remains one of the most important pieces on web architecture.

"What makes a cool URI? A cool URI is one which does not change. What sorts of URIs change? URIs don't change: people change them."

— Tim Berners-Lee, 1998

The essay makes a deceptively simple argument: when you publish a URL, you make a promise. That URL is a permanent name for a resource. When you change or delete it, you break that promise and damage the web.

The Web as a Tapestry

The web is built on links. Every hyperlink is an act of trust—the author believes the destination will exist when readers click it. When links break:

  • Citations become dead ends
  • Bookmarks become useless
  • Search results lead nowhere
  • The web's interconnected knowledge graph fragments

What Causes URLs to Break?

Berners-Lee identifies several common causes of link rot, all of which are choices made by people—not technical necessities.

Technology in the URL

URLs that expose implementation details break when technology changes:

// These URLs reveal technology that will eventually be replaced:
/cgi-bin/search.pl?q=widgets
/scripts/catalog.asp?id=123
/products.php?category=5
/api/v1/servlet/ProductServlet

// When you migrate from PHP to Node, from .NET to Go,
// every one of these URLs breaks

Author Name or Status

Organizing by author or department creates fragility:

// What happens when Sarah leaves the company?
/~sarah/research/2024/paper.html
/users/sarah/documents/report.pdf

// What happens when departments reorganize?
/marketing/campaigns/summer-2024.html
/engineering/docs/api-guide.html

Subject Classification

Taxonomies change, but URLs shouldn't:

// "Smartphones" didn't exist as a category in 2005
/electronics/phones/smartphones/iphone.html

// What was once "new media" is now just "media"
/content/new-media/podcasts/

// Topics get reclassified as understanding evolves
/science/astronomy/pluto-planet.html  // Oops

File Extensions

Extensions leak implementation and constrain the future:

// Today it's HTML, tomorrow it might be:
// - Server-rendered from a database
// - Generated by a static site builder
// - Dynamically assembled
/about-us.html
/about-us.htm
/about-us.shtml
/about-us.php

Arbitrary Reorganization

The most common cause: someone decides to "clean up" the URL structure:

// Original (worked for years)
/products/widgets

// "Improved" version (breaks all existing links)
/catalog/items/widgets
/shop/products/widgets
/store/catalog/widgets-and-gadgets

Designing URLs That Last

A URL should be as permanent as a book's ISBN or a building's street address. Here's how to design for longevity.

Principle 1: Omit Technology

Never put implementation details in URLs:

// Bad: Technology visible
/cgi-bin/products.pl
/servlet/ProductDisplay
/products.aspx

// Good: Technology hidden
/products
/products/widgets
/catalog/2024/widgets

Your URL should work whether your site is built with PHP, Rails, Django, Next.js, or technology that doesn't exist yet.

Principle 2: Omit Ownership

Don't organize by who created or manages content:

// Bad: Organizational structure visible
/marketing/press-releases/2024
/engineering/blog/new-api
/~jsmith/papers/research.html

// Good: Organized by content, not creator
/press/2024
/blog/new-api
/research/papers/machine-learning

Principle 3: Use Dates Carefully

Dates in URLs make sense for time-bound content:

// Good: Blog posts are inherently dated
/blog/2024/11/new-feature-announcement

// Good: News articles are dated
/news/2024/11/27/product-launch

// Bad: Documentation version shouldn't be a date
/docs/2024/api-reference  // Will this be invalid in 2025?

// Better: Version numbers or "latest"
/docs/v2/api-reference
/docs/latest/api-reference

Principle 4: Use Semantic Paths

URLs should describe the resource, not how to get it:

// Bad: Describes the action/mechanism
/getProduct?id=123
/search?category=electronics&sort=price
/display/article/456

// Good: Describes the resource
/products/123
/products/electronics
/articles/456

Principle 5: Plan for Decades

When designing a URL structure, ask: "Will this still make sense in 20 years?"

// Likely to survive:
/products/widget-pro
/articles/introduction-to-web-development
/help/getting-started

// Unlikely to survive:
/featured/hot-new-items-fall-2024
/trending/viral-content
/flash/interactive-demo

When URLs Must Change

Sometimes change is unavoidable. When it is, handle it responsibly.

Use Permanent Redirects

HTTP 301 (Moved Permanently) tells browsers and search engines where content has moved:

// Server configuration (Apache .htaccess)
Redirect 301 /old-page.html /new-page

// Server configuration (nginx)
location /old-page.html {
    return 301 /new-page;
}

// Server code (Node.js/Express)
app.get('/old-page.html', (req, res) => {
    res.redirect(301, '/new-page');
});

A 301 redirect:

  • Preserves bookmarks (browsers learn the new location)
  • Transfers SEO value to the new URL
  • Maintains links from external sites
  • Keeps citations working

Maintain Redirects Forever

The redirect from old to new should last as long as the new page exists. "Cleaning up" old redirects breaks links just as badly as deleting pages.

// Redirect chain over years:
// 2010: /products/widget → (original)
// 2015: /products/widget → /catalog/widgets (moved)
// 2020: /catalog/widgets → /shop/widgets (moved again)

// All three URLs should still work in 2024
// Old links from 2010 might still be out there

Handle Content Removal

When content is genuinely removed (not moved), use HTTP 410 (Gone):

// 404: Not Found (might never have existed, temporary error)
// 410: Gone (definitely existed, permanently removed)

// Server code
app.get('/discontinued-product', (req, res) => {
    res.status(410).send('This product has been discontinued.');
});

410 tells search engines to remove the page from indexes, while 404 might be retried.

Archive Rather Than Delete

Instead of removing old content:

// Instead of deleting:
DELETE /blog/2018/outdated-article

// Archive it with a note:
/blog/2018/outdated-article
<!-- Banner: "This article is from 2018 and may be outdated.
    See /blog/2024/updated-article for current information." -->

Archived content with dates and context is still valuable. Broken links are not.

Real-World Examples

Good: Wikipedia

Wikipedia URLs are remarkably stable:

// Simple, semantic, technology-free:
https://en.wikipedia.org/wiki/URL

// Underscores for spaces (consistent convention)
https://en.wikipedia.org/wiki/Tim_Berners-Lee

// Redirects for common misspellings and aliases
https://en.wikipedia.org/wiki/WWW → redirects to World_Wide_Web

Wikipedia article URLs from 2004 still work today.

Good: W3C Specifications

W3C uses dated URLs for specifications:

// Specific version (permanent)
https://www.w3.org/TR/2023/REC-css-color-4-20231107/

// Latest version (redirects to current)
https://www.w3.org/TR/css-color-4/

Both patterns are useful: dated URLs for citations, "latest" for general reference.

Bad: Government Sites

Government sites often reorganize with every administration change:

// Links from 2016 → broken by 2020
// Links from 2020 → broken by 2024
// Critical civic information becomes inaccessible

Bad: Corporate Rebrands

When companies rebrand, URLs often break entirely:

// Company renames: Acme Inc → Apex Corp
// Old URLs (broken):
https://acme.com/products
https://acme.com/support/docs

// No redirects set up
// All external links, bookmarks, and citations break

Implementation Strategies

URL Mapping Layer

Separate your URL structure from your internal file organization:

// Don't serve files directly:
/var/www/html/products/electronics/phones/widget-pro.html

// Use a routing layer:
/products/widget-pro → renders from database
                      → or loads /templates/product.html
                      → or serves /content/widget-pro.md

This decouples URLs from storage, allowing internal reorganization without breaking public links.

Redirect Registry

Maintain a permanent record of all URL changes:

// redirects.json (or database table)
{
  "redirects": [
    {
      "from": "/old/path",
      "to": "/new/path",
      "date": "2024-03-15",
      "reason": "URL structure redesign",
      "permanent": true
    }
  ]
}

// This registry should be:
// - Version controlled
// - Never have entries removed
// - Automatically applied by the server

URL Linting

Add URL quality checks to your development process:

// Check for anti-patterns:
function lintUrl(url) {
  const issues = [];

  // Technology in URL
  if (/\.(php|asp|jsp|cgi)$/i.test(url)) {
    issues.push('Avoid file extensions');
  }

  // Implementation details
  if (/servlet|handler|controller/i.test(url)) {
    issues.push('Avoid implementation terms');
  }

  // User paths
  if (/\/~\w+\/|\/users?\//i.test(url)) {
    issues.push('Avoid user-based paths');
  }

  return issues;
}

URL Monitoring

Regularly check that your URLs still work:

// Automated link checking
// Run periodically (weekly/monthly)
// Check:
// - Internal links between pages
// - Links from external sites (via search console)
// - Redirect chains (detect long chains)
// - 404 rates (sudden spikes indicate problems)

The Broader Philosophy

Berners-Lee's essay reflects a deeper philosophy about the web.

The Web as Shared Space

When you publish a URL, you're not just creating a page—you're adding an address to a shared namespace. That address becomes part of the web's infrastructure:

  • Search engines index it
  • People bookmark it
  • Other sites link to it
  • Researchers cite it
  • Archives preserve it

Breaking a URL affects everyone who relied on it, not just you.

Stewardship vs Ownership

You don't truly "own" your URLs in isolation. You're a steward of part of the web's address space. Good stewardship means:

  • Planning for permanence
  • Redirecting when necessary
  • Archiving rather than deleting
  • Considering external dependencies

The Cost of Convenience

Breaking URLs is often done for short-term convenience:

  • "It's easier to start fresh"
  • "No one uses those old pages"
  • "Our new CMS works differently"
  • "The redesign requires new URLs"

These choices trade the web's long-term health for immediate convenience. The accumulated damage of millions of such decisions has created today's link rot crisis.

"There are no reasons at all for changing URIs. You can think of some. But the costs should be high for any decision to change URIs. I mean, the effort should be to make them design them and not change them."

— Tim Berners-Lee

Further Reading