HTTP

Status Code

308 Permanent Redirect

Permanent redirect that preserves the HTTP method. Learn when to use 308 instead of 301 for method-sensitive permanent redirects.

4 min read intermediate Try in Playground

What is 308 Permanent Redirect?

TL;DR: 308 Permanent Redirect is like 301 but preserves the HTTP method. Use for API migrations where POST must stay POST.

A 308 Permanent Redirect status code means the resource has permanently moved to a new URL, and clients must use the exact same HTTP method when accessing the new location. Think of it like a business that permanently moved to a new address but kept the same services—you still need to use the same type of request (POST for orders, PUT for updates) at the new location.

This is the method-preserving version of 301 Moved Permanently, ensuring API endpoints maintain their HTTP method semantics after migration.

When Does This Happen?

You’ll see a 308 Permanent Redirect response in these common situations:

1. API Endpoint Migration

Old: POST /v1/api/orders
New: POST /v2/api/orders
Permanent API version upgrade

2. Domain Migration for APIs

Old: PUT /api/users/123 on old-api.com
New: PUT /api/users/123 on new-api.com
Company domain change

3. Service Restructuring

Old: DELETE /admin/posts/456
New: DELETE /cms/posts/456
Permanent service reorganization

4. Protocol Upgrade with Method Preservation

Old: PATCH http://api.example.com/data
New: PATCH https://api.example.com/data
Permanent HTTPS-only policy

5. Microservice Extraction

Old: POST /monolith/payments
New: POST /payments-service/payments
Permanent service separation

Example Responses

API Version Migration:

HTTP/1.1 308 Permanent Redirect
Location: https://api.example.com/v2/orders
Cache-Control: max-age=31536000
Content-Type: text/html

<!DOCTYPE html>
<html>
<body>
<h1>API Endpoint Moved Permanently</h1>
<p>This endpoint has permanently moved to our v2 API.</p>
<p>Please update your code to use: <code>https://api.example.com/v2/orders</code></p>
</body>
</html>
```text

**Domain Migration:**

```http
HTTP/1.1 308 Permanent Redirect
Location: https://new-domain.com/api/users/123
Cache-Control: max-age=31536000
X-Migration-Notice: Please update your API base URL

<html><body>API has permanently moved to new-domain.com</body></html>

Service Extraction:

HTTP/1.1 308 Permanent Redirect
Location: https://payments.example.com/process
Cache-Control: max-age=31536000
X-Service-Migration: payments-microservice

<html><body>Payment processing moved to dedicated service</body></html>
```text

## Real-World Example

Imagine you're migrating an e-commerce API from v1 to v2 and need to preserve HTTP methods:

**Original API Request:**

```http
PUT /v1/api/products/12345 HTTP/1.1
Host: shop.example.com
Content-Type: application/json
Authorization: Bearer token123

{
  "name": "Updated Product Name",
  "price": 29.99,
  "inventory": 150
}

308 Redirect Response:

HTTP/1.1 308 Permanent Redirect
Location: https://shop.example.com/v2/api/products/12345
Cache-Control: max-age=31536000
X-API-Migration: v1-to-v2
Content-Type: text/html

<!DOCTYPE html>
<html>
<head><title>API Migrated</title></head>
<body>
<h1>API Endpoint Permanently Moved</h1>
<p>Our v1 API has been permanently migrated to v2.</p>
<p>New endpoint: <code>https://shop.example.com/v2/api/products/12345</code></p>
<p>All HTTP methods and functionality remain the same.</p>
</body>
</html>
```text

**Client Follows Redirect (Same Method):**

```http
PUT /v2/api/products/12345 HTTP/1.1
Host: shop.example.com
Content-Type: application/json
Authorization: Bearer token123

{
  "name": "Updated Product Name",
  "price": 29.99,
  "inventory": 150
}

308 vs Other Redirect Codes

CodeMethod PreservationDurationSEO ImpactUse Case
308✅ GuaranteedPermanentTransfers rankingAPI migrations, method-critical redirects
301❓ Maybe (browser dependent)PermanentTransfers rankingGeneral permanent redirects
307✅ GuaranteedTemporaryNo transferTemporary method-preserving redirects
302❓ MaybeTemporaryNo transferGeneral temporary redirects

SEO and API Benefits

Search Engine Behavior:

  • Transfers PageRank from old URL to new URL
  • Preserves API endpoint rankings in developer searches
  • Updates search results to show new URLs

API Client Benefits:

  • Existing code continues to work without modification
  • HTTP methods remain semantically correct
  • Gradual migration without breaking changes

Common Mistakes

❌ Using 301 for API endpoints

PUT /v1/api/users/123
HTTP/1.1 301 Moved Permanently  ← Might become GET
Location: /v2/api/users/123  ← Should use 308
```text

**❌ Using 308 when method can change**

```http
GET /old-page → should become different content type
HTTP/1.1 308 Permanent Redirect  ← 301 would be fine

❌ Short cache times for permanent redirects

HTTP/1.1 308 Permanent Redirect
Cache-Control: max-age=300  ← Too short for permanent redirect
```text

**✅ Correct usage**

```http
POST /v1/api/orders
HTTP/1.1 308 Permanent Redirect
Location: https://api.example.com/v2/orders
Cache-Control: max-age=31536000

Best Practices

Use Long Cache Times:

HTTP/1.1 308 Permanent Redirect
Location: /new-permanent-endpoint
Cache-Control: max-age=31536000  ← 1 year
```http

**Provide Migration Information:**

```http
HTTP/1.1 308 Permanent Redirect
Location: /v2/api/endpoint
X-Migration-Guide: https://docs.example.com/v1-to-v2-migration
X-Deprecation-Date: 2026-06-01

Use Absolute URLs:

HTTP/1.1 308 Permanent Redirect
Location: https://new-api.example.com/endpoint  ✓
Location: /endpoint  ✗ (relative URLs discouraged)
```javascript

## Implementation Examples

**Express.js API Migration:**

```javascript
// Redirect all v1 API calls to v2
app.use('/v1/api/*', (req, res) => {
  const newPath = req.path.replace('/v1/api', '/v2/api')
  const newUrl = `https://api.example.com${newPath}`
  res.redirect(308, newUrl)
})

Nginx Configuration:

# Permanent redirect preserving method
location /old-api/ {
    return 308 https://new-api.example.com$request_uri;
}
```javascript

**Python Flask:**

```python
from flask import redirect, request

@app.route('/v1/api/<path:endpoint>', methods=['GET', 'POST', 'PUT', 'DELETE'])
def redirect_v1_api(endpoint):
    new_url = f'https://api.example.com/v2/api/{endpoint}'
    return redirect(new_url, code=308)

Migration Strategy

Phase 1: Implement 308 Redirects

PUT /v1/users/123 → 308 → PUT /v2/users/123
```text

**Phase 2: Update Documentation**

```markdown
# API Migration Notice

v1 endpoints now redirect to v2
Update your base URL to avoid redirects

Phase 3: Monitor and Deprecate

HTTP/1.1 308 Permanent Redirect
X-Deprecation-Warning: v1 API will be removed on 2026-12-01

Browser and Client Behavior

Automatic Method Preservation:

  • All modern HTTP clients preserve the method
  • Request body is resent exactly as originally sent
  • Authentication headers are maintained

Caching Behavior:

  • Browsers cache 308 redirects aggressively
  • Subsequent requests go directly to new URL
  • Reduces server load from redirect processing

Try It Yourself

Visit our request builder and test permanent method preservation:

  1. Set method to PUT
  2. Set path to /v1/demo-endpoint
  3. Add JSON body with update data
  4. Click Send request
  5. Watch the 308 redirect preserve the PUT method

Frequently Asked Questions

What does 308 Permanent Redirect mean?

308 means the resource has permanently moved to a new URL and the client must use the same HTTP method when accessing the new location. It is the method-preserving version of 301.

What is the difference between 308 and 301?

308 guarantees the HTTP method is preserved (POST stays POST). 301 may change POST to GET in some browsers. Use 308 for API migrations where method preservation is critical.

When should I use 308 vs 307?

Use 308 for permanent redirects where the method must be preserved. Use 307 for temporary redirects. Both preserve the HTTP method, but 308 can be cached long-term.

Does 308 transfer SEO value like 301?

Yes, 308 transfers PageRank and SEO value to the new URL just like 301. Search engines treat both as permanent redirects for ranking purposes.

Keep Learning