How to Load Files as ArrayBuffer in Vite

How to load files like fonts as ArrayBuffers in Vite, with an example for embedding custom fonts when using Satori or @vercel/og for dynamic OG images.

Vite normally handles files like .ttf fonts by returning their URLs. That works for most cases, but sometimes you need the imported data in a different format.

I encountered this when trying to generate dynamic Open Graph images with @vercel/og. The API allows you to embed fonts directly, but it expects the font data as an ArrayBuffer.

#Why I Didn't Use fetch for Loading Fonts

Vercel's own documentation shows an example of loading fonts via fetch from a URL - either from Google Fonts or from a local file.

I first tried the local file approach, but when deploying to Vercel, I ran into a cross-origin issue. While it worked fine locally, in production the font failed to load reliably.

#Using vite-plugin-arraybuffer

Short on time, I turned to vite-plugin-arraybuffer, which offered a simpler and more reliable solution in my case.

This small plugin lets you import binary files as ArrayBuffers simply by adding a query parameter to the import path:

app/routes/api/og-image.ts
import InterLatin400 from "./inter-latin-400-normal.ttf?arraybuffer";
import InterLatin700 from "./inter-latin-700-normal.ttf?arraybuffer";

This syntax is similar to other Vite asset import options, such as ?url for explicit URL imports or ?raw for importing files as strings and made it straightforward to pass font data to ImageResponse:

app/routes/api/og-image.ts
export async function loader({ request }: Route.LoaderArgs) {
  // ...
  return new ImageResponse(<div></div>, {
    fonts: [
      { name: "Inter", data: InterLatin400, style: "normal", weight: 400 },
      { name: "Inter", data: InterLatin700, style: "normal", weight: 700 },
    ],
  });
}

#TypeScript Support

The plugin also includes TypeScript support out of the box:

tsconfig.json
{
  "compilerOptions": {
    "types": ["vite-plugin-arraybuffer/types"]
  }
}