Deprecation
Warning before removing
Additive changes let you add features without breaking anyone. But sometimes you need to remove things. Maybe v1 needs to go away. Maybe a specific endpoint is being replaced. You can’t just delete it overnight. Clients depend on it.
Deprecation is the process of telling clients: “This still works today, but it’s going away. Start moving.” It gives them time to migrate before you actually remove anything.
The Deprecation header
RFC 8594 defines a standard HTTP header for this. It’s called Deprecation, and it tells clients that the endpoint or version still works but will be removed.
HTTP/1.1 200 OK
Deprecation: true
Link: <https://api.example.com/docs/migration>; rel="deprecation" Deprecation: true means “this is deprecated.” The Link header points to the migration documentation so clients know where to go for instructions.
You can also specify when the deprecation started:
Deprecation: Sat, 01 Jan 2025 00:00:00 GMT The Sunset header
RFC 8594 also defines Sunset. While Deprecation says “this is going away,” Sunset says “this will stop working on this specific date.”
HTTP/1.1 200 OK
Deprecation: true
Sunset: Sun, 01 Jun 2025 00:00:00 GMT Together, these headers tell a clear story: “This still works today, but it will stop working on June 1, 2025. You have until then to migrate.”
Think of Deprecation as the warning and Sunset as the deadline.
Adding deprecation headers in Hectoday HTTP
The Version Routers lesson showed onResponse adding headers to every response. Here’s how to set up deprecation for the entire v1 API:
export const app = setup({
onRequest: ({ request }) => {
const url = new URL(request.url);
const version = url.pathname.startsWith("/v2") ? "v2" : "v1";
return { apiVersion: version };
},
onResponse: ({ response, locals }) => {
response.headers.set("X-API-Version", locals.apiVersion ?? "v1");
if (locals.apiVersion === "v1") {
response.headers.set("Deprecation", "true");
response.headers.set("Sunset", "Sun, 01 Jun 2025 00:00:00 GMT");
response.headers.set(
"Link",
'<https://api.example.com/docs/v2-migration>; rel="deprecation"',
);
}
return response;
},
routes: [...v1Routes, ...v2Routes],
}); Try it:
curl -i http://localhost:3000/v1/books You should see Deprecation: true, Sunset, and Link in the response headers. Now try v2:
curl -i http://localhost:3000/v2/books Clean headers. No deprecation. v2 responses are unaffected.
Deprecating individual endpoints
Sometimes you don’t want to deprecate the entire version. Maybe just one endpoint is being replaced:
route.get("/v2/books/popular", {
resolve: () => {
const books = getPopularBooks();
return new Response(JSON.stringify(formatBooksV2(books)), {
headers: {
"Content-Type": "application/json",
Deprecation: "true",
Sunset: "Mon, 01 Sep 2025 00:00:00 GMT",
Link: '<https://api.example.com/docs/use-top-instead>; rel="deprecation"',
},
});
},
}); In this case, /v2/books/popular is deprecated, and clients should use /v2/books/top instead. The rest of v2 is perfectly fine and has no deprecation headers.
Deprecating individual fields
What about when you want to remove just one field from a response? For field-level deprecation, you include both the old and new field during the transition period:
// v2 response: author_name is deprecated, use author object
{
"id": "book-1",
"title": "Kindred",
"author": { "id": "author-3", "name": "Octavia Butler" },
"author_name": "Octavia Butler" // DEPRECATED: use author.name
} Both fields exist at the same time. Clients using author_name still work. New clients use author.name. After the sunset date, you remove author_name.
This is exactly how production APIs handle field-level changes. The next lesson covers the full four-step process for field renaming and removal.
Exercises
Exercise 1: Add Deprecation and Sunset headers to all v1 responses via onResponse. Verify they appear on v1 but not v2.
Exercise 2: Deprecate a single v2 endpoint (not the whole version). Add deprecation headers only to that endpoint.
Exercise 3: Include both old and new field names in a response (field-level deprecation). Document which is deprecated.
What is the difference between the Deprecation and Sunset headers?