Async Handlers

Just Return a Value — Fastify Sends It

Async Handlers

An async handler can return a value that becomes the JSON body, or throw an error that Fastify maps to an HTTP status.

4 min read Level 2/5 #fastify#async#errors
What you'll learn
  • Return a value to send a 200 with JSON
  • Throw to surface an error response
  • Use httpErrors helpers for proper status codes

In Fastify, the simplest handler is an async function that returns the response body. No res.json(...) calls; the framework handles serialization and status codes.

Return a Value

app.get('/posts/:id', async (req) => {
  const post = await db.posts.find(req.params.id);
  if (!post) throw app.httpErrors.notFound('Post not found');
  return post;
});

If the handler resolves with a value, Fastify sends 200 OK with the JSON-serialized payload. If it throws, the error flows into Fastify’s error handler.

Throw to Error

The @fastify/sensible plugin adds a httpErrors helper:

await app.register(import('@fastify/sensible'));

app.get('/secret', async (req) => {
  if (!req.headers.authorization) {
    throw app.httpErrors.unauthorized('Missing token');
  }
  return { ok: true };
});

Each helper sets the correct status and message: badRequest, unauthorized, forbidden, notFound, conflict, internalServerError, and more.

Mixing Return and Reply

You can use reply.code(...) alongside returning a value:

app.post('/users', async (req, reply) => {
  const user = await db.users.create(req.body);
  reply.code(201);
  return user;
});

Do not call both reply.send(...) and return value in the same async handler — pick one or Fastify will warn about a double send.

The Reply Object →