Dead simple dynamic image generation server for Bun using Satori + Sharp
rectram is a lightweight file-based image server framework that allows you to generate dynamic images (OG images, social cards, custom graphics) from JSX components using Satori and Sharp. Inspired by @vercel/og, it supports:
- File-based routing (
pages/.../page.tsx) - Dynamic props with
getProps - Satori-powered SVG generation
- Sharp-powered PNG rendering (fast af 🔥)
- Full Bun-native support
- Dynamic Image Pages: Just create a
page.tsxunderpages/and it becomes a route. - Async Props: Fetch data or generate props dynamically with
getProps. - High Performance: Sharp handles PNG conversion fast, perfect for real-time OG image generation.
- Bun Native: No Node.js hacks needed — runs fully in Bun.
project/
├─ pages/
│ ├─ index/page.tsx # default route
├─ assets/
│ ├─ Inter-Regular.ttf
│ ├─ Inter-Italic.ttf
│ ├─ Inter-Bold.ttf
│ └─ Inter-BoldItalic.ttf
├─ src/
│ ├─ index.ts # Bun server entrypoint
│ ├─ router.ts # file-based router
│ ├─ renderer.ts # Satori + Sharp helpers
│ └─ types.ts # Type definitions
├─ bunfig.toml
└─ package.json / bun.lockb
- If you want your own version, use this repo as a template on GitHub:
- Go to the repo → Use this template → Create a new repo under your account.
git clone https://github.com/YOUR_USERNAME/YOUR_REPO.git
cd YOUR_REPO
bun install// pages/index/page.tsx
export const getProps = async ({ query }) => ({
title: query.get("title") ?? "Hello World",
subtitle: query.get("subtitle") ?? "Generated with rectram",
});
export default function Page({ title, subtitle }) {
return (
<div style={{
display: "flex",
width: "100%",
height: "100%",
alignItems: "center",
justifyContent: "center",
background: "#111827",
color: "white",
fontFamily: "Inter",
padding: 64
}}>
<div style={{ display: "flex", flexDirection: "column", gap: 16, maxWidth: 900 }}>
<div style={{ fontSize: 72, fontWeight: 700, lineHeight: 1.1 }}>{title}</div>
<div style={{ fontSize: 36, opacity: 0.9 }}>{subtitle}</div>
</div>
</div>
);
}bun devhttp://localhost:3000/?title=Hello&subtitle=rectram
- Add new routes by creating
page.tsxfiles underpages/. - Fetch dynamic data using
getProps. - Use plain inline styles for your components.
- Fonts must be placed under
assets/and imported inrenderer.ts.
- Returns PNG by default; SVG is optional via
contentType. - Fully typed with TypeScript.
- Made with love and ChatGPT 😋
Apache License 2.0 — do whatever the fuck you want w/ it.