Skip to content

Tech stack

Vumbnail is Cloudflare-native end to end. Compute, storage, config, billing state, and the edge cost-control layer are all Cloudflare primitives, with a Bun

  • TypeScript monorepo on top.
LayerChoiceRole
Runtime / package managerBun (≥1.3)dev, build, test, scripts
LanguageTypeScript 5.8everything
ComputeCloudflare Workersthumbnail serving, accounts/webhooks, API
Edge pre-filterCloudflare Snippethot-set watermark short-circuit (cost)
Persistent storeCloudflare R2 (vumbnail-thumbnails)clean/wm variants, negative cache, memos
Hot config / allow-listCloudflare KV (THUMBNAIL_CONFIG)entitlement projection, processed-event dedup
Billing record of truthCloudflare D1 (vumbnail-billing-entitlements)subscription entitlements + audit
AsyncCloudflare Queuesvideo-metadata observation (flagged)
Image transformPhoton (WASM), default; Cloudflare Images legacywatermark overlay
DeployWranglerper-app Workers deploys
  • Thumbnail Worker (apps/thumbnail) — the product core; plain Worker fetch handler with the cache/source/watermark libraries. No web framework on the hot path.
  • Accounts Worker (apps/accounts) — Hono app handling the Stripe webhook and entitlement sync.
  • API Worker (apps/api) — Hono + tRPC with Better Auth; serves the operator dashboard’s metrics endpoints. Most generic starter-kit routers (user/organization) are unused stubs.
  • Marketing site (apps/astro, apps/web) — Astro static site at astro.vumbnail.com, reached via a service binding for non-thumbnail paths.
  • Operator dashboard (apps/local-dash) — React 19 + TanStack Router + Jotai + Tailwind v4 + shadcn/ui.
  • Shopify app (apps/shopify) — React Router 7 embedded app + theme extension (planned).
  • Stripe — subscription billing; Checkout custom fields carry the domains/IPs to allow-list. API version 2026-02-25.clover.
  • @repo/videos — provider metadata resolution (Vimeo/YouTube oEmbed, player config, password handling, size mapping).
  • External resolvers — a playlist resolver service and a Vimeo relay (noembed.com by default) for fallback resolution.
  • Drizzle ORM + Neon Postgres — auth tables (Better Auth) for the dashboard; not where billing lives (that’s D1).
  • GitHub API — the accounts Worker commits customers.json as a third entitlement store.
  • Vitest (+ Happy DOM) for tests, including Worker and Snippet contract tests.
  • Biome for lint/format, with a stricter agentic overlay (biome.agentic.jsonc) run on touched files via bun run lint:touched.
  • Opt-in stricter TypeScript presets per package (packages/typescript-config/agentic-*.jsonc).
  • Repo conventions: trunk-based development, scripts written in the docs/tiger style, and a hard Cloudflare cost guardrail (any change ≥ $1/month needs a written estimate in docs/ first).

Beyond the core, the repo contains animated-thumbnail-renderer-worker / anim-worker (animated rendering), video-metadata-worker (queue consumer), playlist-resolver(-worker), outreach, email, and three legacy-vumbnail-* apps retained from the pre-Cloudflare (Vercel) era. See Deployment topology.