Skip to content

No programmatic API to load registered fonts at build time #16139

Description

@yanxi-tao

Astro Info

Astro                    v6.1.1
Node                     v24.3.0
System                   macOS (arm64)
Package Manager          bun
Output                   static
Adapter                  none
Integrations             @astrojs/sitemap

If this issue only occurs in one browser, which browser is a problem?

No response

Describe the Bug

❯ bun run build
$ astro build
22:58:02 [vite] Re-optimizing dependencies because vite config has changed
22:58:03 [content] Syncing content
22:58:03 [content] Synced content
22:58:03 [types] Generated 202ms
22:58:03 [build] output: "static"
22:58:03 [build] mode: "static"
22:58:03 [build] directory: /Users/yanxitao/code/oasis/dist/
22:58:03 [build] Collecting build info...
22:58:03 [build] ✓ Completed in 209ms.
22:58:03 [build] Building static entrypoints...
22:58:03 [assets] Copying fonts (20 files)...
22:58:03 [vite] ✓ built in 441ms
22:58:03 [vite] ✓ built in 16ms
22:58:03 [build] Rearranging server assets...

 generating static routes
Unable to connect. Is the computer able to access the url?
error: script "build" exited with code 1

Astro's font system downloads and manages fonts via astro.config.ts and exposes them to CSS through fontData from astro:assets. However, there is no supported way to load the raw font bytes for use in server-side tools such as Satori (OG image generation)

Current behavior

fontData['--font-my-font'][n].src[n].url returns a /_astro/fonts/... URL path. The only way to get the raw bytes is to fetch() that URL against a base, which requires a running server:

fetch(new URL(url, SITE.url)).then(r => r.arrayBuffer())

This fails silently at build time because no dev server is running. In which case, it makes one difficult to statically bulk generate OG images.

The workaround of resolving fonts from node_modules/.astro/fonts/ directly relies on undocumented internal paths that may change across Astro versions.

What's the expected result?

fontData should expose either the raw ArrayBuffer directly, or an absolute filesystem path to the cached font file, so that integrations can load font bytes without network access. A dedicated helper would be ideal:

import { loadFont } from 'astro:assets';

const data = await loadFont('--font-google-sans-code', { weight: '700' });

This would eliminate the need to fetch() against a running server, work consistently across dev and build.

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-hwxkbnaa?file=src%2Fpages%2F%5Bslug%5D.ts

Participation

  • I am willing to submit a pull request for this issue.

Metadata

Metadata

Labels

feat: assetsRelated to the Assets feature (scope)triage: skippedCannot triage in CI

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions