---
title: "Understanding The HTTP Deprecation Header"
description: "The HTTP Deprecation header informs clients that an API endpoint is or will be deprecated. The date can be in the past (deprecated) or future (to be deprecated)."
canonicalUrl: "https://zuplo.com/learning-center/http-deprecation-header"
pageType: "learning-center"
authors: "adrian"
tags: "API Best Practices, API Lifecycle Management, Tutorial"
image: "https://zuplo.com/og?text=Understanding%20the%20HTTP%20Deprecation%20Header"
---
The HTTP Deprecation header is used to inform clients that an API endpoint is or
will be deprecated. According to the recently released
[RFC 9745](https://datatracker.ietf.org/doc/html/rfc9745), the field should be
an [RFC 9651 Date](https://datatracker.ietf.org/doc/html/rfc9651#name-dates),
which is expressed in Unix time. The date can either be in the past (the API has
already been deprecated) or can be in the future (the API will be deprecated at
this date). Here's an example for an API that was deprecated Friday, June 30,
2023 at 23:59:59 UTC:

```yaml
Deprecation: @1688169599
```

## Benefits of Implementing the Deprecation Header

- **Additional Warning**: Your API consumers may not read the deprecation
  warning you send out via email/other comms so this is another way for them to
  become aware of the impending deprecation
- **Maintain in Code**: In comparison to docs (which are often decoupled from
  your API code) the deprecation header is sent by the API at runtime and can be
  updated directly by the developers.
- **Tooling Support**: API clients can eventually adopt a pattern of inspecting
  network responses for the deprecation header and logging a warning in
  non-production environments

## Other Deprecation Header Formats

This convention has not always been the case, and many API providers stray from
the format. Some prefer to use the
[RFC 7231 HTTP-date format](https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.1.1)
(often expressed in GMT) instead, which looks like this:

```yaml
Deprecation: Wed, 11 Oct 2023 23:59:59 GMT
```

The obvious benefit of this format is that it's much more easily readable by an
API developer inspecting network responses. Some tooling (ex. API clients) might
find this format more difficult to parse than unix time however.

Even simpler still is using a boolean instead of a date:

```yaml
Deprecation: true
```

As a binary answer to the question "is this API deprecated?". The drawback of
the boolean is that is necessitates communicating the API's deprecation ahead of
time through other means than the headers. Given that the deprecation header is
not widely adopted, this process is usually necessary anyways. The other
drawback is that it limits API client libraries' ability to warn you of an
upcoming deprecation.

## Extending the HTTP Deprecation Header

Although the deprecation header is useful on its own, you can actually couple it
with other headers as a part of a holistic API deprecation process.

### The Deprecation Link Relation Type

You can use the link relation type to communicate more information about the
deprecation of the API. For example, you can link to documentation or a blog
post about the deprecation like this:

```yaml
Link:
  <https://developer.example.com/deprecation>; rel="deprecation";
  type="text/html"
```

This can be particularly useful if more than just a single endpoint is being
deprecated. One limitation of the HTTP deprecation header is that it doesn't
provide context on the scope of the deprecation - is the whole API being
deprecated, or just this endpoint? Using a link should help with filling in that
gap.

### The HTTP Sunset Header

[Sunsetting](./2025-08-17-how-to-sunset-an-api.mdx) is the point in time in
which the deprecated API becomes unresponsive. The HTTP sunset header
([RFC 8594](https://datatracker.ietf.org/doc/html/rfc8594)) is typically used to
convey when the sunset will occur. This is often coupled with the deprecation
header to give a full picture of the API's end-of-life.

```yaml
Deprecation: @1688169599
Sunset: Sun, 30 Jun 2024 23:59:59 UTC
```

Note that the sunset header uses a different date format than the deprecation
header due to "historical reasons".

## Implementing the HTTP Deprecation Header

Below are some code samples on how to implement the deprecation header in
various popular API frameworks.

### Node.js with Express

```typescript
const express = require("express");
const app = express();

app.get("/v1/old-endpoint", (req, res) => {
  const deprecationDate = Math.floor(Date.now() / 1000); // Unix time
  res.set("Deprecation", `@${deprecationDate}`);
  res.json({ message: "This endpoint is deprecated." });
});

app.listen(3000, () => console.log("Server running on port 3000"));
```

### Python with Flask

```python
from flask import Flask, make_response
from datetime import datetime

app = Flask(__name__)

@app.route('/v1/old-endpoint')
def old_endpoint():
    response = make_response({'message': 'This endpoint is deprecated.'})
    deprecation_date = int(datetime(2023, 10, 11, 23, 59, 59).timestamp())
    response.headers['Deprecation'] = deprecation_date
    return response

if __name__ == '__main__':
    app.run(port=3000)
```

### Java with Spring Boot

```java

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.temporal.*;

@RestController
public class ApiController {

    @GetMapping("/v1/old-endpoint")
    public ResponseEntity<String> oldEndpoint() {
        String deprecationDate = Instant.now().getEpochSecond()
        return ResponseEntity.ok()
                .header("Deprecation", deprecationDate)
                .body("This endpoint is deprecated.");
    }
}
```

### Go with net/http

```go
package main

import (
    "fmt"
    "net/http"
    "time"
)

func oldEndpoint(w http.ResponseWriter, r *http.Request) {
    deprecationDate := time.Now().Unix()
    w.Header().Set("Deprecation", deprecationDate)
    w.Header().Set("Sunset", "Wed, 11 Nov 2023 23:59:59 GMT")
    fmt.Fprintln(w, `{"message": "This endpoint is deprecated."}`)
}

func main() {
    http.HandleFunc("/v1/old-endpoint", oldEndpoint)
    http.ListenAndServe(":3000", nil)
}
```

### PHP with [Laravel](/learning-center/laravel-api-tutorial)

```php
<?php

use Illuminate\Support\Facades\Route;

Route::get('/v1/old-endpoint', function () {
    $deprecationDate = time();
    return response()->json(['message' => 'This endpoint is deprecated.'])
        ->header('Deprecation', $deprecationDate);
});
```

### Parsing the Deprecation Header Client Side

There's no use in sending the header if you don't use it client-side. Here's a
simple javascript example:

```typescript
fetch("/v1/old-endpoint")
  .then((response) => {
    const deprecationHeader = response.headers.get("Deprecation");
    if (deprecationHeader) {
      const deprecationDate = new Date(parseInt(deprecationHeader) * 1000);
      console.warn(
        `This API was deprecated on ${deprecationDate.toUTCString()}`,
      );
    }
    return response.json();
  })
  .then((data) => {
    console.log(data);
  });
```

## Implementing the HTTP Deprecation Header with Zuplo

You can add Deprecation headers in your application code (as in the examples
above), or by using an API Gateway such as
[Zuplo](https://zuplo.com/?utm_source=website&utm_medium=learning_center&utm_campaign=http_deprecation_header).

Doing it at the gateway often works better: deprecation stays in one place
instead of scattered across services, you can change dates or add a Sunset or
Link header without a backend redeploy, and it works the same whether your
backend is Node, Go, or something else.

If your API runs behind
[Zuplo](https://zuplo.com/?utm_source=website&utm_medium=learning_center&utm_campaign=http_deprecation_header),
you can add these headers on the **outgoing response** using the **Set Headers**
(outbound) policy on any route that serves a deprecated endpoint.

1. In the Zuplo dashboard, open your project and go to **Policies**.
2. Add a new policy of type **Set Headers** (outbound), i.e.
   `set-headers-outbound`.
3. Configure the headers you want on the response. The policy takes an array of
   `name`/`value` pairs:

```json
{
  "name": "deprecation-headers",
  "policyType": "set-headers-outbound",
  "handler": {
    "export": "SetHeadersOutboundPolicy",
    "module": "$import(@zuplo/runtime)",
    "options": {
      "headers": [
        { "name": "Deprecation", "value": "@1688169599" },
        { "name": "Sunset", "value": "Sun, 30 Jun 2024 23:59:59 GMT" },
        {
          "name": "Link",
          "value": "<https://developer.example.com/deprecation>; rel=\"deprecation\"; type=\"text/html\""
        }
      ]
    }
  }
}
```

4. Attach this policy to the route(s) for your deprecated endpoint. Every
   response from that route will then include these headers. You can use
   different policies per route if deprecation dates or links vary.

This keeps deprecation in one place (the gateway), works with any backend
language, and makes it easy to add or remove deprecation without redeploying
your service. For full lifecycle support, including brownouts and sunset
windows, combine this with Zuplo’s
[Brown Out policy](https://zuplo.com/docs/policies/brownout-inbound?utm_source=website&utm_medium=learning_center&utm_campaign=http_deprecation_header&utm_content=brownout_policy)
and our [guide on sunsetting APIs](./2025-08-17-how-to-sunset-an-api.mdx).

<CalloutDoc
  title="HTTP Deprecation Policy"
  description="Set Deprecation, Sunset, and Link headers on outgoing responses following the IETF HTTP Deprecation Header standard. No backend changes required."
  href="https://zuplo.com/docs/policies/http-deprecation-outbound?utm_source=website&utm_medium=learning_center&utm_campaign=http_deprecation_header&utm_content=http_deprecation_policy"
  icon="lightning"
/>

## Try It Yourself

<CalloutSample
  title="HTTP Deprecation Example"
  description="A complete working example that adds Deprecation, Sunset, and Link headers to API responses. Deploy directly to your Zuplo account or run locally."
  deployUrl="https://zuplo.com/examples/http-deprecation"
  localCommand="npx create-zuplo-api --example http-deprecation"
  repoUrl="https://github.com/zuplo/zuplo/tree/main/examples/http-deprecation"
/>

## Alternatives to the HTTP Deprecation Header

There are only a handful of alternatives in terms of runtime indication of
deprecation status.

### Legacy: Using the HTTP Warning Header

The HTTP Warning header is a general-purpose header that carries additional
information about the status or transformation of a message. It's primarily used
to warn clients about potential issues that might not be reflected in the status
code.

The Warning header uses a three-digit warning code, an optional agent (usually
the hostname), and a warning text enclosed in double quotes. The 299 warning
code is ideal for indicating deprecation because it's a persistent warning that
can convey any miscellaneous message.

```yaml
Warning: 299 - "Deprecated API: This endpoint is deprecated and will be removed on 2023-11-11."
```

Some companies like UKG have
[documented this pattern](https://developer.ukg.com/hcm/docs/api-deprecation-strategy#adding-a-warning-header-to-responses)
but these APIs likely predate the introduction of the deprecation header.

#### Pros and Cons of Using the Warning Header

**Pros**

- Standardized Format: The Warning header is part of the HTTP specification.
- Client Awareness: Many HTTP clients and browsers are designed to handle
  Warning headers.
- Flexibility: Allows for detailed messages about the deprecation.

**Cons**

- Less Specific: Not specifically designed for deprecation notices.
- Possible Misinterpretation: Clients might associate warnings with caching
  issues rather than deprecation.

I'd recommend that you steer clear of using the warning header and reserve it
for actual runtime issues. Recall the deprecated APIs are still supposed to be
functional until sunset. Now how would you report an actual issue if the warning
header is being occupied by a deprecation message?

### Unorthodox: Use the JSON Response Body

Depending on the format of your API response, you can include additional
properties that are parsed at runtime.

```json
{
  "deprecated": 1688169599,
  "sunset": "2023-11-11T23:59:59Z",
  "data": {...}
}
```

I suppose the only benefit is that developers are more likely to look at
response bodies than they are at headers - but its impossible for API client
tooling to adopt this pattern, which is a bad tradeoff. Additionally, how would
you deprecate an API that doesn't return JSON? Don't try this in prod, kids.

## The Deprecation Header is Just the Start

Although the HTTP deprecation header is helpful in the process of deprecating an
API—there's a lot more you need to know. The deprecation header is one part of a
full lifecycle: planning, communicating, brownouts, and sunset. The following
resources will help you run that process well.

<CalloutDoc
  title="Deprecating REST APIs"
  description="A full guide to deprecating REST APIs: planning timelines, communicating with consumers, brownouts, and sunset."
  href="https://zuplo.com/learning-center/deprecating-rest-apis?utm_source=website&utm_medium=learning_center&utm_campaign=http_deprecation_header&utm_content=deprecating_rest_apis"
  icon="book"
  features={[
    "Deprecation lifecycle",
    "Communication strategies",
    "Sunset and brownouts",
  ]}
/>