Open-SEO Performance Optimizations: Build-Time and Runtime Strategies for Cloudflare Workers
Open-SEO uses build-time pruning, lazy loading, and edge caching to keep Cloudflare Workers isolates under 128 MB and minimize cold-start latency.
Open-SEO is an open-source SEO platform built for Cloudflare Workers that implements aggressive performance optimizations to ensure sub-second cold starts and efficient memory usage. According to the every-app/open-seo source code, the codebase combines custom Vite plugins, strategic dynamic imports, and multi-tier edge caching to eliminate bloat and reduce external API latency. These optimizations target the unique constraints of edge compute isolates, where memory and startup time directly impact user experience.
Build-Time Optimizations via Custom Vite Plugin
The foundation of Open-SEO's performance strategy starts at build time. The repository includes a custom plugin that surgically removes heavy dependencies from the eager startup graph before deployment.
Pruning Heavy Dependencies with EAGER_DENYLIST
In vite-plugin-lean-worker-bundle.ts, the plugin defines an EAGER_DENYLIST that automatically stubs dead-weight packages like just-bash and workers-ai-provider. During the generateBundle phase, it walks the static-import closure of the worker entry chunk and aborts the build if any forbidden module appears in the eager bundle.
The plugin also replaces node_modules/zod/v4/locales/index.* with an English-only barrel file, eliminating internationalization overhead that would otherwise inflate the bundle. This ensures the worker isolate stays lean and responsive.
Conditional Sourcemap Emission
To reduce artifact size in production, sourcemaps are only emitted when the POSTHOG_SOURCEMAPS environment flag is true. As configured in vite.config.ts (lines 42–44), this prevents unnecessary megabytes from being deployed to the edge when error tracking is disabled.
// vite.config.ts
import { leanWorkerBundle } from "./vite-plugin-lean-worker-bundle";
export default defineConfig({
plugins: [
leanWorkerBundle(),
// …other plugins
],
build: {
sourcemap: process.env.POSTHOG_SOURCEMAPS === "true",
},
});
Runtime Memory Optimizations
Keeping the worker isolate under the 128 MB Cloudflare Workers limit requires careful memory management at runtime.
Lazy Loading the 3 MB DataForSEO SDK
Rather than statically importing the DataForSEO SDK—which weighs approximately 3 MB—Open-SEO uses a dynamic import pattern. The barrel file at src/server/lib/dataforseo/sections.ts re-exports SDK functions but is never eagerly loaded. Instead, loadDataforseoSections() is called only when a user explicitly initiates a keyword-research flow:
// Called only when user triggers DataForSEO feature
export async function loadDataforseoSections() {
const sections = await import("@/server/lib/dataforseo/sections");
return sections;
}
The leanWorkerBundle plugin enforces this by rejecting any accidental eager import of the SDK subtree, keeping the baseline heap small.
In-Process Cache Deduplication
Within the SAM chat Durable Object (src/server/features/sam/SamChatAgent.ts), repeated writes to the public origin are automatically deduplicated via the in-process cache. By storing the origin via this.ctx.storage.put, subsequent turns eliminate per-request storage costs entirely.
Edge Caching Strategies
Open-SEO layers two Cloudflare storage services—R2 and KV—to minimize repeated external API calls and serve data from the edge.
R2 Object Cache with Deterministic Keys
For DataForSEO results, the system implements a soft-TTL cache in src/server/lib/r2-cache.ts. The buildCacheKey function generates a SHA-256 digest of request parameters, creating deterministic keys. The setCached helper stores results with an expiresAt metadata field, implementing expiration without database writes:
import { buildCacheKey, getCached, setCached, CACHE_TTL } from "@/server/lib/r2-cache";
async function fetchSerpAnalysis(params: Record<string, unknown>) {
const cacheKey = await buildCacheKey("serp:analysis", params);
const cached = await getCached(cacheKey);
if (cached) return cached as SerpResult;
const fresh = await callDataforseoApi(params);
await setCached(cacheKey, fresh, CACHE_TTL.researchResult);
return fresh;
}
KV Hot-Read Cache for Semi-Static Data
Large datasets like SERP location lists and Ahrefs ratings rarely change. These are cached in Cloudflare KV with aggressive TTLs: 30 days for locations (src/server/lib/dataforseo/serp-locations.ts) and 24 hours for Ahrefs ratings (src/server/lib/ahrefs.ts). The KV cacheTtl option allows Workers to serve these directly from the edge on repeated requests:
const KV_HOT_READ_TTL_SECONDS = 60 * 60 * 24 * 30; // 30 days
async function getSerpLocations(iso: string) {
const cached = await env.KV.get(`serp-locations:${iso}`, {
cacheTtl: KV_HOT_READ_TTL_SECONDS,
});
if (cached) return JSON.parse(cached);
const fresh = await fetchFromOrigin(iso);
await env.KV.put(`serp-locations:${iso}`, JSON.stringify(fresh));
return fresh;
}
Compute Cost Controls
Before executing expensive operations, Open-SEO validates that the user has sufficient credits to prevent wasted infrastructure resources.
Scoped Credit Gates
In src/server/features/sam/SamChatAgent.ts, the beforeTurn method (lines 33–49) checks credit balances before invoking LLM calls or DataForSEO API requests. This prevents wasted compute on unauthenticated requests or exhausted accounts, protecting both infrastructure costs and response latency.
Summary
- Build-time pruning: The custom
vite-plugin-lean-worker-bundle.tsstubs heavy dependencies and enforces an eager-module deny-list to keep bundles small. - Lazy loading: The 3 MB DataForSEO SDK is dynamically imported only when needed via
src/server/lib/dataforseo/sections.ts. - Edge caching: SHA-256-keyed R2 cache with soft TTL and KV hot-read patterns reduce external API calls for semi-static data.
- Memory safety: In-process deduplication and conditional sourcemap emission keep worker isolates under 128 MB.
- Cost protection: Credit checks in
SamChatAgent.tsgate expensive operations before execution.
Frequently Asked Questions
How does Open-SEO keep its bundle size small for Cloudflare Workers?
Open-SEO uses a custom Vite plugin (vite-plugin-lean-worker-bundle.ts) that defines an EAGER_DENYLIST of heavy dependencies. The plugin stubs packages like workers-ai-provider and swaps the full Zod locale barrel for an English-only version. During generateBundle, it validates that no forbidden modules entered the eager graph, failing the build if violations are detected.
Why does Open-SEO use both R2 and KV for caching?
The platform uses KV for small, semi-static datasets (SERP locations, Ahrefs ratings) that benefit from global edge replication and 30-day TTLs. R2 stores larger, frequently updated DataForSEO results with deterministic SHA-256 keys and soft TTL metadata. This tiered approach optimizes for both read latency (KV) and storage cost (R2).
When is the DataForSEO SDK loaded in Open-SEO?
The approximately 3 MB SDK is never statically imported into the eager bundle. Instead, src/server/lib/dataforseo/sections.ts exports SDK functions that are only accessed via a dynamic import inside loadDataforseoSections(). This ensures the SDK is pulled exclusively when a user runs a DataForSEO-based feature, keeping cold-start memory minimal.
How does Open-SEO prevent wasted compute on expensive API calls?
Before executing LLM calls or DataForSEO requests, SamChatAgent.ts runs a credit check in its beforeTurn lifecycle hook. If the user lacks sufficient credits, the operation aborts immediately, preventing unnecessary external API latency and protecting infrastructure costs.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →