Skip to main content
HTVG’s WASM-based architecture makes it perfect for edge runtimes. Run SVG compilation at the edge with sub-10ms latency worldwide.

Why Edge Runtimes?

Global Distribution

Run your code in data centers close to your users

Low Latency

WASM execution is extremely fast — typical compilation takes 5-10ms

No Cold Starts

Edge workers stay warm, unlike traditional serverless functions

Cost Efficient

Pay only for execution time, with generous free tiers

Cloudflare Workers

Cloudflare Workers is the recommended edge runtime for HTVG, with native WASM module support.
1

Install dependencies

npm install htvg
npm install -D wrangler
2

Configure wrangler.toml

wrangler.toml
name = "htvg-worker"
main = "src/index.ts"
compatibility_date = "2024-01-01"

[build]
command = "npm run build"

# WASM module bundling is automatic with Wrangler 3+
3

Create worker with WASM import

src/index.ts
import { init, compileDocument, type HtvgDocument } from "htvg";
// Cloudflare Workers handles .wasm imports natively
import wasmModule from "htvg/htvg.wasm";

export default {
  async fetch(request: Request): Promise<Response> {
    // Initialize WASM once per request (or cache globally)
    await init(wasmModule);

    const url = new URL(request.url);

    if (url.pathname === "/api/svg" && request.method === "POST") {
      try {
        const doc: HtvgDocument = await request.json();
        const result = compileDocument(doc);

        return new Response(result.svg, {
          headers: {
            "Content-Type": "image/svg+xml",
            "Cache-Control": "public, max-age=3600"
          }
        });
      } catch (e) {
        return Response.json(
          { error: e instanceof Error ? e.message : "Unknown error" },
          { status: 400 }
        );
      }
    }

    return new Response("HTVG Worker", { status: 200 });
  }
};
4

Deploy

npx wrangler deploy
Wrangler 3+ automatically bundles .wasm imports. For older versions, use wasm_modules in wrangler.toml.

Complete Cloudflare Worker Example

Here’s a production-ready worker with multiple endpoints:
src/index.ts
import { init, compileDocument, version, type HtvgDocument } from "htvg";
import wasmModule from "htvg/htvg.wasm";

let initialized = false;

export default {
  async fetch(request: Request): Promise<Response> {
    // Initialize WASM once
    if (!initialized) {
      await init(wasmModule);
      initialized = true;
    }

    const url = new URL(request.url);

    // POST /api/compile — compile a document
    if (url.pathname === "/api/compile" && request.method === "POST") {
      try {
        const doc: HtvgDocument = await request.json();
        const result = compileDocument(doc);
        return Response.json({
          svg: result.svg,
          width: result.width,
          height: result.height,
          warnings: result.warnings
        });
      } catch (e) {
        const msg = e instanceof Error ? e.message : String(e);
        return Response.json({ error: msg }, { status: 400 });
      }
    }

    // GET /api/version
    if (url.pathname === "/api/version") {
      return Response.json({ version: version() });
    }

    // GET /api/og — generate OG image from query params
    if (url.pathname === "/api/og") {
      const title = url.searchParams.get("title") || "Untitled";
      const subtitle = url.searchParams.get("subtitle") || "";

      const result = compileDocument({
        meta: { width: 1200, height: 630 },
        content: {
          type: "flex",
          style: {
            width: 1200,
            height: 630,
            padding: 80,
            backgroundColor: "#0f172a",
            flexDirection: "column",
            justifyContent: "center",
            gap: 24
          },
          children: [
            {
              type: "text",
              content: title,
              style: { fontSize: 72, fontWeight: 700, color: "#f8fafc" }
            },
            subtitle ? {
              type: "text",
              content: subtitle,
              style: { fontSize: 32, color: "#94a3b8" }
            } : null
          ].filter(Boolean) as any
        }
      });

      return new Response(result.svg, {
        headers: {
          "Content-Type": "image/svg+xml",
          "Cache-Control": "public, max-age=86400"
        }
      });
    }

    return new Response("HTVG Edge Worker", { status: 200 });
  }
};

Vercel Edge Functions

Deploy HTVG to Vercel’s edge network:
api/svg.ts
import { init, compileDocument } from "htvg";
import { NextRequest, NextResponse } from "next/server";

export const config = {
  runtime: "edge"
};

let initialized = false;

export default async function handler(req: NextRequest) {
  if (!initialized) {
    // Fetch WASM module from public directory
    const wasmUrl = new URL("/htvg_bg.wasm", req.url);
    const wasmResponse = await fetch(wasmUrl);
    const wasmBuffer = await wasmResponse.arrayBuffer();
    await init(wasmBuffer);
    initialized = true;
  }

  if (req.method === "POST") {
    const doc = await req.json();
    const result = compileDocument(doc);

    return new NextResponse(result.svg, {
      headers: {
        "Content-Type": "image/svg+xml",
        "Cache-Control": "public, max-age=3600"
      }
    });
  }

  return new NextResponse("Method not allowed", { status: 405 });
}

Deno Deploy

Deno has first-class TypeScript and WASM support:
main.ts
import { init, compileDocument } from "npm:htvg";

let initialized = false;

async function initWasm() {
  if (!initialized) {
    // Load WASM from URL or local file
    const wasmUrl = "https://unpkg.com/htvg/dist/wasm/htvg_bg.wasm";
    const wasmResponse = await fetch(wasmUrl);
    const wasmBuffer = await wasmResponse.arrayBuffer();
    await init(wasmBuffer);
    initialized = true;
  }
}

Deno.serve(async (req) => {
  await initWasm();

  const url = new URL(req.url);

  if (url.pathname === "/api/svg" && req.method === "POST") {
    const doc = await req.json();
    const result = compileDocument(doc);

    return new Response(result.svg, {
      headers: {
        "Content-Type": "image/svg+xml",
        "Cache-Control": "public, max-age=3600"
      }
    });
  }

  return new Response("HTVG on Deno Deploy");
});
Deploy with:
deployctl deploy --project=htvg-demo main.ts

Performance Optimization

Cache the WASM initialization globally to avoid repeated setup:
let wasmInitialized = false;

export default {
  async fetch(request: Request) {
    if (!wasmInitialized) {
      await init(wasmModule);
      wasmInitialized = true;
    }
    // ... rest of handler
  }
};
Use Cloudflare KV or similar for caching:
const cacheKey = `svg:${JSON.stringify(doc)}`;
let cached = await KV.get(cacheKey);

if (!cached) {
  const result = compileDocument(doc);
  await KV.put(cacheKey, result.svg, { expirationTtl: 3600 });
  cached = result.svg;
}

return new Response(cached, {
  headers: { "Content-Type": "image/svg+xml" }
});
For large SVGs, stream the response:
const result = compileDocument(doc);
const stream = new ReadableStream({
  start(controller) {
    controller.enqueue(new TextEncoder().encode(result.svg));
    controller.close();
  }
});

return new Response(stream, {
  headers: { "Content-Type": "image/svg+xml" }
});

Environment Comparison

RuntimeWASM SupportSetup ComplexityCold StartGlobal Distribution
Cloudflare WorkersNativeEasy~0ms300+ locations
Vercel EdgeVia fetchModerate~10ms30+ regions
Deno DeployNativeEasy~5ms35+ regions
AWS Lambda@EdgeVia layersComplex~100ms13+ regions
Cloudflare Workers is recommended for production HTVG deployments due to native WASM support and zero cold starts.

CORS Configuration

If your edge function serves an API, add CORS headers:
const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type"
};

export default {
  async fetch(request: Request) {
    // Handle preflight
    if (request.method === "OPTIONS") {
      return new Response(null, { headers: corsHeaders });
    }

    // ... your logic

    return new Response(result.svg, {
      headers: {
        ...corsHeaders,
        "Content-Type": "image/svg+xml"
      }
    });
  }
};

Example Deployments

Live Demo

Interactive playground on Cloudflare Workers

GitHub Repo

Source code and examples

OG Images

Generate Open Graph images at the edge

API Reference

Full API documentation

Custom Fonts

Use web fonts in edge deployments

Examples

Real-world use cases

Build docs developers (and LLMs) love