# Sending Response

> H3 automatically converts any returned value into a web response.

Values returned from [Event Handlers](/guide/basics/handler) are automatically converted to a web [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) by H3.

**Example:** Simple event handler function.

```js
const handler = defineHandler((event) => ({ hello: "world" }));
```

H3 smartly converts handler into:

```js
const handler = (event) =>
  new Response(JSON.stringify({ hello: "world" }), {
    headers: {
      "content-type": "application/json;charset=UTF-8",
    },
  });
```

> [!TIP]
> 🚀 H3 uses srvx `FastResponse` internally to optimize performances in Node.js runtime.

If the returned value from event handler is a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) or from an [async function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function), H3 will wait for it to resolve before sending the response.

If an error is thrown, H3 automatically handles it with error handler.

<read-more></read-more>

## Preparing Response

Before returning a response in main handler, you can prepare response headers and status using [`event.res`](/guide/api/h3event#eventres).

```js
defineHandler((event) => {
  event.res.status = 200;
  event.res.statusText = "OK";
  event.res.headers.set("Content-Type", "text/html");
  return "<h1>Hello, World</h1>";
});
```

> [!NOTE]
> If a full [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response/Response) value is returned, prepared status is discarded and headers will be merged/overriden. For performance reasons, it is best to only set headers only from final Response in this case.

> [!NOTE]
> If an Error happens, prepared status and headers will be discarded. The recommended way to include headers in error responses is via `new HTTPError({ headers })`. As a last resort for headers that need to be set implicitly before the error is known (e.g., CORS), you can use `event.res.errHeaders` — these will be merged into error responses automatically.

## Response Types

H3 smartly converts JavaScript values into web [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response/Response).

### JSON Serializable Value

Returning a [JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON) serializable value (**object**, **array**, **number** or **boolean**), it will be stringified using [JSON.stringify()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) and sent with default `application/json` content-type.

**Example:**

```ts
app.get("/", (event) => ({ hello: "world" }));
```

> [!TIP]
> Returned objects with `.toJSON()` property can customize serialization behavior. Check [MDN docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) for more info.

### String

Returning a string value, sends it as plain text body.

> [!NOTE]
> If not setting `content-type` header, it can default to `text/plain;charset=UTF-8`.

**Example:** Send HTML response.

```ts
app.get("/", (event) => {
  event.res.headers.set("Content-Type", "text/html;charset=UTF-8");
  return "<h1>hello world</h1>";
});
```

You can also use `html` utility as shortcut.

```js
import { html } from "h3";

app.get("/", () => html("<h1>hello world</h1>"));
```

### `Response`

Returning a web [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response/Response), sends-it as final reponse.

**Example:**

```ts
app.get("/", (event) => new Response("Hello, world!", { headers: { "x-powered-by": "H3" } }));
```

> [!IMPORTANT]
> When sending a `Response`, any [prepared headers](#preparing-response) that set before, will be merged as default headers. `event.res.{status,statusText}` will be ignored. For performance reasons, it is best to only set headers only from final `Response`.

### `ReadableStream` or `Readable`

Returning a [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) or Node.js [`Readable`](https://nodejs.org/api/stream.html#readable-streams) sends it as stream.

### `ArrayBuffer` or `Uint8Array` or `Buffer`

Send binary [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer), [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) or node [Buffer](https://nodejs.org/api/buffer.html#buffer).

`content-length` header will be automatically set.

### `Blob`

Send a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) as stream.

`Content-type` and `Content-Length` headers will be automatically set.

### `File`

Send a [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) as stream.

`Content-type`, `Content-Length` and `Content-Disposition` headers will be automatically set.

## Special Types

Some less commonly possible values for response types.

### `null` or `undefined`

Sends a response with empty body.

> [!TIP]
> If there is no `return` statement in event handler, it is same as `return undefined`.

### `Error`

Retuning an [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) instance will send it.

> [!IMPORTANT]
> It is better to `throw` errors instead of returning them. This allows proper propagation from any nested utility.

<read-more></read-more>

### `BigInt`

Value will be sent as stringified version of BigInt number.

> [!NOTE]
> Returning a JSON object, does not allows BigInt serialization. You need to implement `.toJSON`. Check [MDN docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) for more info.

### `Symbol` or `Function`

**Returning Symbol or Function has undetermined behavior.** Currently, H3 sends a string-like representation of unknown Symbols and Functions but this behavior might be changed to throw an error in the future versions.

There are some internal known Symbols H3 internally uses:

- `Symbol.for("h3.notFound")`: Indicate no route is found to throw a 404 error.
- `Symbol.for("h3.handled")`: Indicate request is somehow handled and H3 should not continue (Node.js specific).
