# Open-SEO Performance Optimizations: Build-Time and Runtime Strategies for Cloudflare Workers

> Discover Open-SEO performance optimizations for Cloudflare Workers. Learn build-time pruning, lazy loading, and edge caching strategies to minimize cold starts and stay under 128MB.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: performance
- Published: 2026-08-02

---

**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`](https://github.com/every-app/open-seo/blob/main/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`](https://github.com/every-app/open-seo/blob/main/vite.config.ts) (lines 42–44), this prevents unnecessary megabytes from being deployed to the edge when error tracking is disabled.

```typescript
// 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`](https://github.com/every-app/open-seo/blob/main/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:

```typescript
// 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`](https://github.com/every-app/open-seo/blob/main/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`](https://github.com/every-app/open-seo/blob/main/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:

```typescript
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`](https://github.com/every-app/open-seo/blob/main/src/server/lib/dataforseo/serp-locations.ts)) and 24 hours for Ahrefs ratings ([`src/server/lib/ahrefs.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/ahrefs.ts)). The KV `cacheTtl` option allows Workers to serve these directly from the edge on repeated requests:

```typescript
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`](https://github.com/every-app/open-seo/blob/main/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.ts`](https://github.com/every-app/open-seo/blob/main/vite-plugin-lean-worker-bundle.ts) stubs 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`](https://github.com/every-app/open-seo/blob/main/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.ts`](https://github.com/every-app/open-seo/blob/main/SamChatAgent.ts) gate 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`](https://github.com/every-app/open-seo/blob/main/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`](https://github.com/every-app/open-seo/blob/main/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`](https://github.com/every-app/open-seo/blob/main/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.