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.
Platform & runtime
Section titled “Platform & runtime”| Layer | Choice | Role |
|---|---|---|
| Runtime / package manager | Bun (≥1.3) | dev, build, test, scripts |
| Language | TypeScript 5.8 | everything |
| Compute | Cloudflare Workers | thumbnail serving, accounts/webhooks, API |
| Edge pre-filter | Cloudflare Snippet | hot-set watermark short-circuit (cost) |
| Persistent store | Cloudflare R2 (vumbnail-thumbnails) | clean/wm variants, negative cache, memos |
| Hot config / allow-list | Cloudflare KV (THUMBNAIL_CONFIG) | entitlement projection, processed-event dedup |
| Billing record of truth | Cloudflare D1 (vumbnail-billing-entitlements) | subscription entitlements + audit |
| Async | Cloudflare Queues | video-metadata observation (flagged) |
| Image transform | Photon (WASM), default; Cloudflare Images legacy | watermark overlay |
| Deploy | Wrangler | per-app Workers deploys |
Application frameworks
Section titled “Application frameworks”- 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 atastro.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).
Integrations & libraries
Section titled “Integrations & libraries”- 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.comby 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.jsonas a third entitlement store.
Tooling
Section titled “Tooling”- 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 viabun 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/tigerstyle, and a hard Cloudflare cost guardrail (any change ≥ $1/month needs a written estimate indocs/first).
Notable monorepo apps
Section titled “Notable monorepo apps”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.