Why I moved from Azure to Vercel
Both Azure Static Web Apps (SWA) and Vercel solve the same problem — host a static site with attached HTTP Functions, with a Git-driven deploy flow and a CDN at the edge. The differences below are what tilt the platform choice for small-to-mid sites in 2026.
Quota Headroom
| Azure SWA Free | Vercel Hobby | |
|---|---|---|
| Apps/Projects | 10 per subscription, not raisable | unlimited |
| Bandwidth | 100 GB / app / month | 100 GB / account / month |
| Custom domains | 2 per app | no per-project cap |
| Pre-production envs | 3 per app (Free) / 10 (Standard) | unlimited preview deployments |
| Deploy artifact size | 250 MB total, 15,000 files | 250 MB compressed per Function |
| Build minutes | (your GitHub Actions quota) | 6,000 / month |
| Function invocations | 100k / day (Consumption-shared) | 1M / month |
| Function triggers | HTTP only | HTTP only (Workflows for non-HTTP) |
| Real-time logs | Application Insights only (boot-delayed) | dashboard + CLI streams |
| Cold-start mitigation | none on Consumption | Fluid Compute + scale-to-one (Pro+) |
The two SWA caps that bind most often: the 10-instance-per-subscription Free limit (with PR/branch envs that's already 5 sites in flight) and the 2-custom-domain-per-app limit — apex+www counts against it, leaving zero room for m.example.com or alternate locales.
Instant Rollback, Deployment Immutability, and the Promote Caveat
Every Vercel deployment is immutable and gets a permanent hash URL (<project>-<hash>-<owner>.vercel.app). The production domain is an alias pointing at one specific deployment ID. From there, two distinct switching mechanisms exist — and they have very different cost profiles:
- Instant Rollback (alias-flip, no rebuild). Re-aliases the production domain to a previously-aliased production deployment. ~1 second, no CI burn, no environment-variable resolution. Hobby rolls back to the immediately previous prod deployment; Pro/Enterprise rolls back to any past prod deployment. This is the genuinely instant, build-free switching primitive.
- Promote a preview to production (rebuild). Vercel's UI literally says "A new deployment will be built using your production environment" — promoting a preview triggers a fresh build with production env vars applied. The reason is build-time tooling, not runtime: browsers can't read env vars (no
process.envin the client), but bundlers (esbuild/webpack), static-site generators, and server-side build code (_data/*.js,getStaticProps, framework-specific) substitute env values into the static bundle and into pre-rendered HTML at build time. If preview and production env values differ — typical for API endpoints, feature flags, orVERCEL_ENVitself — the produced bytes differ. Vercel can't tell whether your specific app uses build-time env, so it rebuilds defensively. Build-cache typically completes in 1–2 minutes for an Eleventy-class project; cold builds take 3–5 minutes. - Stage and manually promote (Pro/Enterprise feature). Builds for production from the start (so production env vars are applied during the build), then waits for a manual promote click before flipping the alias. The closest thing to a true "build once, promote later" workflow on Vercel.
Retention is generous: by default Vercel keeps the last 10 deployments, the last 20 production Ready, the last 20 non-production Ready, and anything ever aliased to production. With no pruning policy configured, every shipped prod deployment stays available for instant rollback indefinitely.
The "ship the change, observe, decide" workflow is therefore well-supported on Vercel: every production deployment is keepable and instantly revertable. What the platform does not default-support is same-bytes test→prod alias-flipping in the standard git push test → preview → promote flow — that path always rebuilds.
SWA equivalent: re-running the GitHub Actions workflow against the previous commit. Multiple minutes of rebuild, GitHub-Actions quota burn, and no platform-level instant rollback. Vercel's Instant Rollback is meaningfully better than SWA on operational recovery time.
Skew Protection
Vercel ships skew protection as a generally-available feature: when a new deployment goes live, in-flight clients on the old version continue to receive their JS chunks, fonts, and API responses from the old deployment URL. The framework appends the deployment ID as ?dpl= query parameter or x-deployment-id header, so versioned requests resolve to the deployment that served the initial page. Configurable retention window: up to 7 days on Enterprise, shorter on lower tiers.
Without this, a long-lived browser tab from before a deployment can fetch a now-deleted chunk-abc123.js and die. SWA has no equivalent — a fresh deploy invalidates the CDN, and clients on the previous version that haven't loaded all their assets get hashed-asset 404s. For static sites the impact is small; for any non-trivial SPA it's a real failure mode that no amount of CI hygiene fixes.
Fluid Compute and Cold Starts
Vercel's Fluid Compute (rolled out 2025, default for new projects in 2026) materially changes serverless economics:
- Bytecode caching on Node 20+ reduces cold-start parse/compile time.
- Scale-to-one keeps a warm instance alive (up to 14 days since last invocation on Pro/Enterprise).
- Predictive scaling pre-warms additional instances ahead of detected load patterns.
- Pricing shifts from pure invocation count to CPU-time consumed — long-running idle waits (DB queries, fetch) cost less than they would on a per-invocation model.
Vercel publishes a 99.37% no-cold-start figure for sustained workloads under Fluid. SWA Managed Functions run on Azure Functions Consumption-tier under the hood, with classic 1–3 s cold starts on Node and no equivalent of scale-to-one. For page-load-time-blocking API calls this difference is observable.
Function Bundle Limits
SWA enforces a 15,000-file cap per deployment across all tiers (Free, Standard, Dedicated). Microsoft's own applicationinsights v3 SDK ships ~33,000 transitive files — the recommended observability SDK literally cannot fit inside a Function bundle on Microsoft's own platform without preprocessing or a hand-rolled HTTP-direct alternative.
Vercel's per-Function cap is 250 MB compressed (effectively post-bundle), which on a typical Node tree is several orders of magnitude more headroom than the SWA file-count cap. Most off-the-shelf SDKs install without surgery.
Operational Visibility
SWA Managed Functions deliberately hide their host. There is no Kudu console, no SCM endpoint, no log-stream pre-boot, no startup-trace blade — none of the diagnostics that a regular Azure Functions app exposes. The Kudu wiki itself notes that "applications cannot access SCM to manage/enumerate/start/stop services" in the Azure Web App sandbox; Managed Functions inherit those restrictions and add more. Application Insights traces only show up after the host has booted, so any pre-boot failure is invisible from the platform's own observability surface.
This blackout window produces several recurring failure modes that consume hours of debugging with no actionable signal:
- Workflow-file drift: SWA's auto-generated GitHub Actions YAML is brittle to small edits. A wrong
app_location, a missingapi_location, anoutput_locationthat doesn't match the framework's actual build output, or a node version mismatch between the WF andpackage.json enginescauses the deploy to fail with generic GitHub Actions errors that don't mention the actual mismatch. The Function host then either doesn't start or starts and serves nothing, with no diagnostic surface to interrogate. - Silent Function non-deployment: Functions can be packaged into the build output, the GitHub Actions run can complete green, the deploy can be marked successful in the Azure portal — and the Functions can still simply not be present at runtime. Comparing against a working reference site is often the only viable debugging path, because the platform exposes no introspection (no
/api/_diagnostic, no list-deployed-functions endpoint, no kudu/zip-deploy log). - Node version mismatches: The Functions host boots without logs when the configured runtime version is incompatible with the function bundle. There is no boot-log to confirm or deny.
Vercel exposes per-deployment realtime logs (build, edge, function) in the dashboard and via CLI with zero configuration, including stderr from cold-start failures. Build logs stream in the browser; runtime logs stream during invocation. The list of deployed functions is visible per-deployment in the dashboard. There is no analog blackout window.
GitHub Integration
Vercel's GitHub App is installed once at the org/account level and is invisible thereafter. Adding a new repo to a Vercel project is a dropdown selection. The integration is bidirectional: PR comments include a deep-link to the preview environment, and merging triggers production deploys.
SWA's GitHub integration is per-app and ties each deployment to a per-app token (AZURE_STATIC_WEB_APPS_API_TOKEN_<RESOURCE>) auto-injected as a repo secret. The auto-generated GitHub Actions workflow file is named after a random default hostname (e.g. brave-forest-007459703.7.azurestaticapps.net) regardless of the resource name, and the default file content depends on the build flow Azure infers. The required PAT permission for any subsequent edit — Secrets: Read+Write — fails with the misleading error RepositoryToken is invalid. Admin rights are required if missing, which reads like a permissions denial rather than a missing scope.
Edge Handling and Custom Domains
Apex-to-www redirect on Vercel is a single checkbox in the Domains panel; Vercel auto-issues Let's Encrypt for both apex and www and serves the redirect at edge. The Vercel-Cloudflare integration handles apex CNAME-flattening automatically.
On SWA, both domains are configured separately and the redirect is wired in staticwebapp.config.json or via DNS-provider page rules. Apex on the Free tier is fiddly without DNS-provider help, and the 2-domain-per-app cap leaves limited room for redirect siblings. The Vercel CDN also tends to win TTFB head-to-heads in EU/US regions in third-party benchmarks.
Tooling and DX
Vercel is a single CLI (vercel) for everything: deploy, env vars, dev server, logs, rollback, domains. SWA needs az staticwebapp for resource ops, func for local Function emulation, swa (the standalone SWA CLI) for the integrated proxy, plus the Azure Portal for App Settings and the GitHub Actions UI for build debugging.
Other DX wins on Vercel:
- Vercel Toolbar on preview deployments: comment threads bound to specific UI elements, per-PR.
- Web Analytics + Speed Insights: built-in core-web-vitals monitoring without an SDK install (free tier sample-rated).
- Preview-URL comments in PRs: GitHub PR gets a deep-link to the preview environment.
- Monorepo first-class support: turborepo, nx, pnpm workspaces detected automatically.
SWA has staging URLs in PR comments but no integrated comment system, no built-in web vitals, no monorepo affordances beyond what GitHub Actions can express.
Documentation and Ecosystem
Vercel's docs are organized end-to-end by workflow (deploy, env vars, custom domains, rollback, …) and read like a single product manual. SWA's docs span Static Web Apps, Azure Functions, App Service, and Application Insights pages on Microsoft Learn, with frequent cross-links and version drift between them. Stack Overflow tags next.js and vercel have an order of magnitude more recent activity than azure-static-web-apps, which translates into faster signal-to-noise on real failure modes.
When Azure SWA still wins
- Sites already deeply integrated with Azure AD, Microsoft Graph, Service Bus, or Functions Durable. SWA's Bring-Your-Own-Functions linking lets you connect a real Azure Functions app for non-HTTP triggers, larger bundles, and Premium-tier cold-start mitigation — best of both worlds inside Azure.
- Sites where the per-app 100 GB bandwidth multiplier is essential. A side project that genuinely sustains 80 GB/month on its own is fine on SWA Free but eats most of a Vercel Hobby account.
- Cost when seat-count is high relative to app-count. SWA Standard is $9/app/month; Vercel Pro is $20/seat/month. SWA wins when
apps × $9 < seats × $20, i.e., for small portfolios with multi-seat teams. Examples: 1 commercial app + 1 operator → SWA $9 vs Vercel $20 (SWA wins); 5 apps + 5 operators → SWA $45 vs Vercel $100 (SWA wins); 10 apps + 1 operator → SWA $90 vs Vercel $20 (Vercel wins). For solo-operator portfolios, Vercel becomes cheaper from ~3 commercial apps onwards. - Az-ecosystem operational lingua franca. Teams that already live in
azCLI, ARM templates, Bicep, and Azure DevOps pay friction for leaving the ecosystem that may outweigh the per-task DX wins.
Bottom line
For low-to-medium-traffic static sites with light Functions and a small operator footprint, Vercel offers strictly more platform-level features (instant rollback, skew protection, Fluid cold starts, immutable deployment retention) and equal-or-better ergonomics across deployment, observability, and tooling. SWA remains competitive on portfolio cost when the per-app bandwidth multiplier is the operative constraint, and is the natural fit when the rest of the stack is Azure-native.
Sources:
- Azure Static Web Apps quotas — Microsoft Learn
- Azure Static Web Apps pricing
- Azure Static Web Apps preview environments — Microsoft Learn
- Azure Static Web Apps branch environments — Microsoft Learn
- Azure SWA FAQ — Managed Functions
- Azure Web App sandbox — SCM access restrictions (Kudu wiki)
- Vercel Hobby plan
- Vercel limits
- Vercel deployment retention
- Vercel instant rollback
- Vercel promoting deployments
- Vercel skew protection
- Vercel Fluid Compute
- Vercel Fluid Compute — scale to one, cold starts