1. Library
  2. Computer Networks
  3. Http and the Web
  4. Status Codes

Updated 9 hours ago

When a server returns 201 Created, it's making a specific announcement: something new exists now that didn't exist before. This isn't just a successful response—it's a birth certificate. The server is telling you: "I made something. It didn't exist before. Now it does. Here's where it lives."

That's different from 200 OK, which just means "your request worked." 201 means your request brought something into existence.

The Location Header: Where the New Thing Lives

A 201 response should include a Location header pointing to the newly created resource:

HTTP/1.1 201 Created
Location: /api/users/124
Content-Type: application/json

{
    "id": 124,
    "name": "Alice",
    "email": "alice@example.com",
    "createdAt": "2024-10-21T14:22:00Z"
}

The Location header answers the immediate question: "Great, you created something—where is it?" Without this header, clients have to parse the response body, find an ID, and construct the URL themselves. The Location header just tells them.

What to Include in the Response Body

Return the complete created resource, including everything the server generated:

POST /api/users HTTP/1.1
Content-Type: application/json

{
    "name": "Alice",
    "email": "alice@example.com"
}

HTTP/1.1 201 Created
Location: /api/users/124
Content-Type: application/json

{
    "id": 124,
    "name": "Alice",
    "email": "alice@example.com",
    "createdAt": "2024-10-21T14:22:00Z",
    "updatedAt": "2024-10-21T14:22:00Z",
    "emailVerified": false
}

The client sent two fields. The server returns six. Those four extra fields—id, createdAt, updatedAt, emailVerified—are the server's contribution. The client needs to see them without making another request.

You can return an empty body and force clients to GET the resource from the Location URL. But that's two round-trips instead of one. Return the resource.

201 vs. 200: Creation vs. Everything Else

The distinction is simple:

201 Created: A new resource now exists that didn't exist before.

200 OK: The request succeeded, but nothing new was created.

Updating an existing user? That's 200:

PUT /api/users/124 HTTP/1.1
{"name": "Alice Updated"}

HTTP/1.1 200 OK

Creating a new user? That's 201:

POST /api/users HTTP/1.1
{"name": "Alice"}

HTTP/1.1 201 Created
Location: /api/users/124

PUT Can Return Either

PUT is interesting because it can create or update depending on whether the resource exists:

PUT /api/users/999 HTTP/1.1
{"name": "Charlie"}

If user 999 doesn't exist, the server creates it and returns 201. If user 999 already exists, the server updates it and returns 200.

The status code tells you what actually happened. First request: 201 (birth). Subsequent requests: 200 (update). You're witnessing creation or maintenance, and the server tells you which.

POST Creates Multiple Resources

POST isn't idempotent. Each request creates a new resource:

POST /api/users → 201 Created, Location: /api/users/124
POST /api/users → 201 Created, Location: /api/users/125
POST /api/users → 201 Created, Location: /api/users/126

Three requests, three new users, three different Location headers. Each 201 announces a distinct creation.

Client Handling

const response = await fetch('/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' })
});

if (response.status === 201) {
    const location = response.headers.get('Location');
    const user = await response.json();
    // user.id, user.createdAt, etc. are now available
}

Check the status code first. 201 means creation succeeded. Then extract both the Location header (where to find it) and the response body (the resource itself).

Common Mistakes

Returning 201 for updates:

PUT /api/users/124  // User already exists
HTTP/1.1 201 Created  // Wrong—should be 200 OK

Returning 201 when creation failed:

POST /api/users
HTTP/1.1 201 Created
{"error": "Email already registered"}  // Wrong—should be 409 Conflict

Omitting the Location header:

HTTP/1.1 201 Created
{"id": 124, "name": "Alice"}  // Where does this resource live?

Always include Location. It's the whole point of 201—not just "I created something" but "I created something and here's where it is."

Frequently Asked Questions About 201 Created

Was this page helpful?

😔
🤨
😃