npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

fastify-arktype

v0.1.0

Published

Fastify type provider, validator/serializer compilers, and @fastify/swagger integration for ArkType

Downloads

182

Readme

fastify-arktype

A Fastify type provider for ArkType. Write route schemas once in ArkType and get:

  • Full TypeScript inference on request.body, request.query, request.params, request.headers, and typed reply.send() — no generics.
  • Runtime validation via ArkType, with Fastify-standard 400 error payloads.
  • OpenAPI generation for @fastify/swagger, powered by ArkType's native toJsonSchema().

The API mirrors fastify-type-provider-zod, so migrating between them is mindless. Note this is a type provider, not a plugin — there's nothing to register(); you set two compilers and a type parameter (see below).

Install

npm install fastify-arktype arktype fastify

Peer dependencies: fastify@^5, arktype@^2, and optionally @fastify/swagger for OpenAPI generation. Node >= 20.

Setup

import Fastify from "fastify";
import { type } from "arktype";
import {
  validatorCompiler,
  serializerCompiler,
  type ArkTypeTypeProvider,
} from "fastify-arktype";

const app = Fastify()
  .setValidatorCompiler(validatorCompiler)
  .setSerializerCompiler(serializerCompiler)
  .withTypeProvider<ArkTypeTypeProvider>();

// Schemas are plain ArkType types — define them anywhere, reuse them across routes.
// Constraints like number>=0 are validated at runtime and flow into the OpenAPI
// doc (minimum: 0), even where TypeScript can only express `number`.
const NewUser = type({ name: "string", age: "number>=0" });
const UserCreated = type({ id: "string.uuid" });

app.post(
  "/users",
  {
    schema: {
      body: NewUser,
      response: { 201: UserCreated },
    },
  },
  async (req, reply) => {
    req.body.name; // string — inferred, no generics
    return reply.code(201).send({ id: crypto.randomUUID() });
  },
);

A runnable app lives in examples/basic.ts.

Query/params coercion with morphs

Fastify passes querystring, params, and headers as string records. Use ArkType's parsing keywords (morphs) to coerce them — the handler sees the schema's output type:

app.get(
  "/items",
  { schema: { querystring: type({ page: "string.numeric.parse" }) } },
  async (req) => {
    req.query.page; // number
    return { page: req.query.page };
  },
);

Morphs also run on responses before serialization. reply.send() accepts the schema's input type and the morph output goes over the wire:

const responseSchema = type({
  createdAt: ["Date", "=>", (d) => d.toISOString()],
});
// handler returns { createdAt: new Date(...) }; the client receives an ISO string

OpenAPI / swagger

import fastifySwagger from "@fastify/swagger";
import fastifySwaggerUI from "@fastify/swagger-ui";
import { jsonSchemaTransform } from "fastify-arktype";

await app.register(fastifySwagger, {
  openapi: {
    openapi: "3.1.1",
    info: { title: "my api", version: "1.0.0" },
  },
  transform: jsonSchemaTransform,
});
await app.register(fastifySwaggerUI, { routePrefix: "/documentation" });

Schemas are converted with ArkType's native toJsonSchema(). Constructs JSON Schema can't represent (morphs, protos like Date, predicates) degrade to their closest representable base schema — a string.numeric.parse querystring documents as a pattern-constrained string — instead of throwing.

To skip routes or customize the conversion:

import { createJsonSchemaTransform } from "fastify-arktype";

transform: createJsonSchemaTransform({
  skipList: ["/healthcheck"],
  // forwarded to Type.toJsonSchema(); see ArkType docs
  toJsonSchemaOptions: { fallback: (ctx) => ctx.base ?? {} },
});

Routes can also set schema: { hide: true } to be excluded from the document. OpenAPI 3.1 is recommended since ArkType emits JSON Schema draft 2020-12.

Error handling

Validation failures return Fastify's standard 400 payload (code: "FST_ERR_VALIDATION"), with per-issue details on error.validation. Response schema mismatches throw a 500 ResponseSerializationError. Customize both with the exported guards:

import {
  hasArkTypeFastifySchemaValidationErrors,
  isResponseSerializationError,
} from "fastify-arktype";

app.setErrorHandler((error, req, reply) => {
  if (hasArkTypeFastifySchemaValidationErrors(error)) {
    // error.validation: [{ keyword, instancePath, message, params: { expected, actual } }]
    return reply
      .code(400)
      .send({ error: "Bad Request", issues: error.validation });
  }
  if (isResponseSerializationError(error)) {
    // error.method, error.url, error.cause (the original ArkErrors)
    return reply.code(500).send({ error: "Internal Server Error" });
  }
  return reply.send(error);
});

Mixing with non-ArkType routes

Setting the compilers app-wide means every schema-bearing route goes through them. A route using plain JSON Schema should supply its own per-route compilers:

app.post(
  "/legacy",
  {
    schema: { body: legacyJsonSchema },
    validatorCompiler: myAjvCompiler, // route-level override
    serializerCompiler: myFastJsonCompiler,
  },
  handler,
);

A non-ArkType response schema without an override fails fast at startup with InvalidSchemaError. The swagger transform, by contrast, passes non-ArkType schemas through untouched, so mixed documents work.

Migrating from fastify-type-provider-zod

Export names match; swap the package and the schemas.

| fastify-type-provider-zod | fastify-arktype | | ------------------------------------------------------------- | ------------------------------------------------------------ | | ZodTypeProvider | ArkTypeTypeProvider | | validatorCompiler | validatorCompiler | | serializerCompiler / createSerializerCompiler | serializerCompiler / createSerializerCompiler | | jsonSchemaTransform / createJsonSchemaTransform | jsonSchemaTransform / createJsonSchemaTransform | | jsonSchemaTransformObject | — (ArkType has no schema registry; schemas are inlined) | | hasZodFastifySchemaValidationErrors | hasArkTypeFastifySchemaValidationErrors | | isResponseSerializationError / ResponseSerializationError | same | | InvalidSchemaError | same | | FastifyPluginAsyncZod / FastifyPluginCallbackZod | FastifyPluginAsyncArkType / FastifyPluginCallbackArkType |

One semantic difference: Zod v4 codecs are bidirectional, so the Zod provider types reply.send() with the schema's output type and encodes back to the wire format. ArkType morphs are one-way (input → output), so here reply.send() takes the input type and the morph produces the wire format.

FAQ

Why not a generic Standard Schema type provider? Standard Schema standardizes validation and inference, but not JSON Schema export. Swagger/OpenAPI generation — half the value of this package — therefore requires library-specific integration, which is why this package is ArkType-specific.

Does it use fast-json-stringify? No. Responses are validated by ArkType, then serialized with JSON.stringify, same as the Zod provider.

License

MIT