The Shape Of The Bill
The important thing to internalize: traffic volume is not the problem.
Edge requests and data transfer sit far inside the included allowance and cost
nothing. Essentially the entire bill is Fast Origin Transfer and Fluid
Active CPU, both of which are billed from zero with no free tier.
The consequence is that spend tracks how bytes are produced, not how many
requests arrive. Adding traffic to a cached route is close to free. Adding one
uncached dynamic route, or one always-on cron, is not.
Why Origin Transfer Dominates
Fast Origin Transfer (4 GB) is ~80% of Fast Data Transfer (5 GB). Origin transfer is only charged when a response travels from a function to the CDN, so that ratio says roughly four out of five bytes we serve bypass the CDN and are generated fresh by a function. That is expected for the authenticated dashboard surface — 343 files across the apps callawait connection(), which is the correct way to opt an authed page
into request-time rendering under cacheComponents. It is not expected for
public surfaces. Any public, unauthenticated route served without
Vercel-CDN-Cache-Control pays origin transfer on every single hit.
apps/web/next.config.ts already demonstrates the pattern for the auth shell:
Cache-Control: max-age=0 keeps the browser honest while
Vercel-CDN-Cache-Control lets the CDN serve the shared copy. Extending this to
public marketing pages, the public form-filling surface at /f/<shareCode>, and
storefront pages is the single largest available reduction in origin transfer.
Region Pricing Is Not Uniform
Function region changes the unit price substantially:sin1 charges 4.5x the iad1 rate for origin transfer.
Do not “fix” this by moving functions to
iad1. Supabase runs in
ap-southeast-1 and SES_DEFAULT_REGION is ap-southeast-1, so sin1 is the
region that keeps functions next to their data. Moving compute to North America
would add a cross-Pacific round trip to every database call. sin1 is the
correct region; the lever is sending fewer bytes from it, not relocating it.platform uses
['sin1', 'iad1', 'fra1']). Requests routed to iad1 or fra1 still reach a
Singapore database, so the extra regions add cross-ocean latency while spreading
deployments wider. Single-region sin1 is usually the better default here.
Always-On Crons
Cron invocations run forever, whether or not anyone is looking at the result. Current scheduled load:infrastructure is the majority of all scheduled work on the account because it
samples at one-minute resolution.
Rules For Adding A Cron
- Prefer a persisted watermark to a fixed lookback. A job that scans from
lastCheckedAtis cadence-independent: slowing it delays the result but never drops work.docker-recovery-alertsis the reference implementation, which is why it safely runs every 5 minutes instead of every minute. - Justify sub-5-minute schedules.
* * * * *is 43,200 invocations per month per job. Onlysample-resourcesearns it, because the monitoring dashboard renders a one-minute series and flags data stale after five minutes (RESOURCE_SAMPLE_MIN_INTERVAL_MS). Changing that cadence means changing that constant too, and accepting coarser graphs. - Ask whether it should be on-demand. A dashboard that is viewed a few minutes a week does not need a 24/7 sampler. Sampling on page view, or behind a feature flag, removes the cost floor entirely.
What Is Already Optimized
Verified, so nobody re-investigates these:- Image optimization —
minimumCacheTTLis 7 days increateTuturuuuNextConfig, not the 60-second default. - Client polling — shared hooks (
use-notifications,use-active-timer-session,use-calendar-sync) all setrefetchIntervalInBackground: false, so hidden tabs stop polling. - Canceled Git deployments —
vercel.jsonsetsgit.deploymentEnabled: false, so pushes create a deployment record that is canceled with 0 build seconds. The long list ofCANCELEDdeployments in the dashboard is cosmetic, not billed. - Preview deployments — the
vercel-preview-*.yamlworkflows areworkflow_dispatchonly and gated onTRUSTED_PREVIEW_DEPLOY_ACTORS. - Builds —
vercel buildruns on GitHub Actions runners, so build compute is not billed as Vercel build minutes. - Web Analytics —
@vercel/analyticsis not mounted in any app, so the per-event meter stays near zero even though the dashboard toggle is on.