Skip to content
EtherCorps
Blog Announcing SvelteKit OG v4: An alternative to @vercel/og for sveltekit 6 min read
Product engineering · Webdev November 2025

Announcing SvelteKit OG v4: An alternative to @vercel/og for sveltekit

Introduction We're thrilled to announce the official release of...

Written by Shivam Meena · EtherCorps

Introduction

We're thrilled to announce the official release of @ethercorps/sveltekit-og@v4! This major version represents a complete architectural overhaul focused on delivering uncompromising stability, simplifying the developer API, and providing the tools needed for robust, high-performance image generation across all Javascript runtimes.

This release introduces powerful new features that eliminate manual steps and complex workarounds.

I learnt a lot while fixing @ethercorps/sveltekit-og like wasm issue, runtime issues and developer experience with typescript.

Resources

Core of the v4

With v4, we focused on fixing issues related to runtime and fonts. We are happy with the results and I hope it makes you happy too.

Runtime Stability & Reliability

The core architecture was rebuilt to ensure cross-runtime reliability, resolving subtle issues related to wasm loading. Images now render flawlessly whether you deploy to:

  • Cloudflare Workers & Pages (@sveltejs/adapter-cloudflare)
  • Workers - Preview
  • Pages - Preview
  • Vercel (@sveltejs/adapter-vercel) - Preview
  • Node.js (@sveltejs/adapter-node) - Clone the example from repo
  • Netlify (@sveltejs/adapter-netlify) - Preview
  • Deno - Preview
  • Bun - Still not supported.

The library now explicitly guides developers toward safer, platform-agnostic patterns, making the setup "rock-solid" out of the box.

Ultimate Font Utilities (v4.2.0 Update)

Loading fonts and managing how to load them remote or locally, It was a pain. The v4.2.0 update introduces multiple fonts utility:

CustomFont: Use this class for local files (read via $app/server/read) or custom remote URLs (read via fetch). Supports lazy loading.

GoogleFont: The easiest way to use remote fonts. It automatically handles fetching the CSS, parsing the .ttf URL, and applying in-memory caching for maximum performance.

resolveFonts: A crucial utility function that transforms your array of font class instances into the final, resolved ArrayBuffer objects required by the underlying Satori engine.

How to use

To get started with @ethercorps/sveltekit-og, checkout -> setup in docs

  • Basic Example: Here, we will use raw html but we can also use svelte components too.
// + src/routes/og/server.ts

import { ImageResponse } from '@ethercorps/sveltekit-og';
import type { RequestHandler } from '@sveltejs/kit';
import JetbrainsRegular from "$lib/fonts/JetBrainsMono-Regular.ttf?url"
import { GoogleFont, CustomFont, resolveFonts } from '@ethercorps/sveltekit-og/fonts';
import { read } from '$app/server';

const template = `
 <div class="bg-gray-50 flex flex-col w-full h-full justify-center">
    <div class="flex flex-col w-full justify-between p-8">
      <h2 class="flex flex-col text-3xl sm:text-4xl font-bold tracking-tight text-gray-900 text-left">
        <span>Ready to dive in?</span>
        <span class="text-indigo-600">Start your free trial today.</span>
      </h2>
      <div class="flex flex-row items-start">
        <div class="flex rounded-md shadow">
          <button class="flex justify-center rounded-md border border-transparent bg-indigo-600 px-5 py-3 text-base font-medium text-white">Get started</button>
        </div>
        <div class="ml-3 flex rounded-md shadow">
          <button class="flex items-center justify-center rounded-md border border-transparent bg-white px-5 py-3 text-base font-medium text-indigo-600">Learn more</button>
        </div>
      </div>
    </div>
  </div>
`;

const jetbrainsMonoBoldURL = 'https://github.com/JetBrains/JetBrainsMono/raw/master/fonts/ttf/JetBrainsMono-Bold.ttf'

const fonts = [
	new CustomFont('JetBrains Mono', () => read(JetbrainsRegular).arrayBuffer(), {weight: 400}),
	new GoogleFont('JetBrains Mono', { weight: 500 }),
	new CustomFont('JetBrains Mono', () => fetch(jetbrainsMonoBoldURL).then((res) => res.arrayBuffer()), { weight: 700 }),
];

export const GET: RequestHandler = async () => {
        // RESOLVE: Convert the class instances to ArrayBuffers
        const resolvedFonts = await resolveFonts([interRegular, interBold]);

	return new ImageResponse(template, {
		height: 400,
		width: 800,
		debug: false,
		fonts: resolvedFonts
	});
};

Preview: Raw html preview

  • Svelte Component Example:

Svelte component which will be converted to png.

// OG.svelte
<script>
	let { text, spanText } = $props();
</script>

<div class="bg-gray-50 flex w-full h-full items-center justify-center">
	<div class="flex flex-col w-full py-12 px-4  p-8">
		<h2 class="flex flex-col text-3xl sm:text-4xl tracking-tight text-gray-900 text-left">
			<span class="font-bold">{text}</span>
			<span class="text-indigo-600 font-normal mt-4">{spanText}</span>
		</h2>
		<div class="mt-8 flex md:mt-0">
			<div class="flex rounded-md shadow">
				<button
					class="flex items-center justify-center rounded-md border border-transparent bg-indigo-600 px-5 py-3 text-base font-medium text-white"
					>Get started</button
				>
			</div>
			<div class="ml-3 flex rounded-md shadow">
				<button
					class="flex items-center justify-center rounded-md border border-transparent bg-white px-5 py-3 text-base font-medium text-indigo-600"
					>Learn more</button
				>
			</div>
		</div>
	</div>
</div>

Sveltekit Api endpoint to generate and serve generated image.

// +server.ts
import OG from './OG.svelte';
import type { RequestHandler } from '@sveltejs/kit';
import { ImageResponse } from '@ethercorps/sveltekit-og';
import { resolveFonts } from '@ethercorps/sveltekit-og/fonts';
import { fonts } from '../../lib/utils/helper.js';

export const GET: RequestHandler = async () => {
	return new ImageResponse(
		OG,
		{
			debug: false,
			height: 600,
			width: 1200,
			fonts: await resolveFonts(fonts)
		},
		{ text: 'Ready to dive in?', spanText: 'Start your free trial today.' }
	);
};

resolveFonts(fonts) is important, so always do it and then pass it to image options.

Helper used for clean code.

// src/lib/utils/helper.js
import { GoogleFont, CustomFont } from '@ethercorps/sveltekit-og/fonts';
import { read } from '$app/server';
import JetbrainsRegular from "./JetBrainsMono-Regular.ttf?url"

const jetbrainsMonoBoldURL = 'https://github.com/JetBrains/JetBrainsMono/raw/master/fonts/ttf/JetBrainsMono-Bold.ttf'

export const fonts = [
	new CustomFont('JetBrains Mono', () => read(JetbrainsRegular).arrayBuffer(), {weight: 400}),
	new GoogleFont('JetBrains Mono', { weight: 500 }),
	new CustomFont('JetBrains Mono', () => fetch(jetbrainsMonoBoldURL).then((res) => res.arrayBuffer()), { weight: 700 }),
];

Preview:

Conclusion

We believe this update delivers the most stable and developer-friendly experience for generating OG images in the SvelteKit OG Image generation ecosystem. As always, feel free to report any issues or suggest improvements on our GitHub repository!

Checkout newly released docs at sveltekit-og.dev

This is me writing for you after a long time. If you wanna ask or suggest anything please put it in comment and show some love ❤️.

webdevsveltesveltekitopensource
All posts

Keep reading

All posts
2026 · 03

Building ContainerKit: GUI for Apple's Container CLI with Tauri and Svelte 5

Introduction I’ve been working on ContainerKit, a desktop application designed to provide...

Product engineering · Opensource
3 min
2024 · 04

Cloudflare Based AI Embed System

This is a submission for the Cloudflare AI Challenge. What I Built I have built a chatbot...

AI & applied ML · Cloudflarechallenge
3 min
EtherCorps mascot

Get in touch

We take on a small number of projects at a time.

Tell us what you're building and where it hurts. We'll say honestly whether we're the right team for it.

Get in touch