<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged vercel</title>
<link>https://coderlegion.com/tag/vercel</link>
<description>Powered by Question2Answer</description>
<item>
<title>Vercel Was Too Expensive, So I Migrated My Next.js App to Cloudflare Workers</title>
<link>https://coderlegion.com/31124/vercel-was-too-expensive-so-i-migrated-my-next-js-app-to-cloudflare-workers</link>
<description>&lt;p&gt;I recently moved production traffic for &lt;a rel=&quot;nofollow&quot; href=&quot;https://galaxymovies.app&quot;&gt;Galaxy Movies&lt;/a&gt;, my Next.js movie/TV discovery site, off Vercel and onto Cloudflare Workers. Nothing against Vercel. Vercel is a great platform, and the app ran happily there for a long time. But I was paying for a Pro plan for what is ultimately a side project, my DNS was already on Cloudflare, and the entire backend surface is fetch-based (Upstash REST, OpenAI, Resend, TMDB); no databases, no TCP. That's about as close to a best-case scenario for running Next.js on workers as you can get.&lt;/p&gt;
&lt;p&gt;The site is Next.js 16 Pages Router, React 19, Chakra UI, with ISR catalog pages, a pile of API routes, four Vercel cron jobs, and dynamic OG images via next/og. Here's what the migration actually looked like, including the parts that fought back.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The adapter: @opennextjs/cloudflare&lt;/strong&gt;&lt;br&gt;
The OpenNext Cloudflare adapter takes a standard next build output and rebundles it into a worker. Setup is two files. First, open-next.config.ts. The interesting bit is the incremental cache override, which points ISR's cache at an R2 bucket:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { defineCloudflareConfig } from '@opennextjs/cloudflare'

import r2IncrementalCache from '@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache'

export default defineCloudflareConfig({

  default: { experimentalBundledNextServer: true },

  incrementalCache: r2IncrementalCache

})
Then wrangler.jsonc:

{

  &quot;main&quot;: &quot;.open-next/entry.js&quot;,

  &quot;name&quot;: &quot;galaxy-movies&quot;,

  &quot;compatibility_flags&quot;: [&quot;nodejs_compat&quot;, &quot;global_fetch_strictly_public&quot;],

  &quot;assets&quot;: { &quot;directory&quot;: &quot;.open-next/assets&quot;, &quot;binding&quot;: &quot;ASSETS&quot; },

  &quot;services&quot;: [{ &quot;binding&quot;: &quot;WORKER_SELF_REFERENCE&quot;, &quot;service&quot;: &quot;galaxy-movies&quot; }],

  &quot;r2_buckets&quot;: [

    { &quot;binding&quot;: &quot;NEXT_INC_CACHE_R2_BUCKET&quot;, &quot;bucket_name&quot;: &quot;galaxy-movies-inc-cache&quot; }

  ],

  &quot;triggers&quot;: { &quot;crons&quot;: [&quot;0 6 * * *&quot;, &quot;30 6 * * *&quot;, &quot;0 7 * * *&quot;, &quot;0 16 * * 5&quot;] },

  &quot;find_additional_modules&quot;: true,

  &quot;rules&quot;: [

    { &quot;type&quot;: &quot;Data&quot;, &quot;globs&quot;: [&quot;public/fonts/**&quot;, &quot;public/backdrop_fallback.jpg&quot;], &quot;fallthrough&quot;: true }

  ]

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Deploy is two commands: opennextjs-cloudflare build then wrangler deploy. Everything below is the gap between &quot;two commands&quot; and &quot;actually works in production.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gotcha 1: Next's dev-only require()s break the bundle&lt;/strong&gt;&lt;br&gt;
The adapter bundles the Next server with esbuild, and esbuild wants every require() to resolve, including dev-only code paths inside Next's own dist files (next-dev-server, setup-dev-bundler, an upgrade nudge) and an RSC-only path (react-server-dom-webpack) that a Pages Router app never executes. They're dead code in production, but dead code still has to resolve.&lt;/p&gt;
&lt;p&gt;I fixed it with patch-package to mark them external in the adapter's bundle step, plus a postbuild script that drops tiny stub modules where the runtime resolution lands:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// scripts/opennext-postbuild.js: runs after opennextjs-cloudflare build

fs.writeFileSync('.../dev/next-dev-server.js', 'module.exports = {}\n')

fs.writeFileSync('.../router-utils/setup-dev-bundler.js', 'module.exports = {}\n')

// ...etc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The patch also adds preview-props.json to the manifest glob the adapter uses, which the Pages Router build emits, and the adapter wasn't collecting. Not elegant, but it's contained in patches/ and reapplied on every npm install by patch-package. If the upstream adapter fixes these, the patch just stops applying cleanly, and I delete it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gotcha 2: next/og picks the wrong runtime&lt;/strong&gt;&lt;br&gt;
This one took the longest. I generate OG images with next/og, which wraps @vercel/og. The library has two entries: a Node build that does readFileSync on a bundled font and calls WebAssembly.instantiate at runtime (both disallowed on workerd), and an edge build that doesn't.&lt;/p&gt;
&lt;p&gt;The problem: OpenNext forces NEXT_RUNTIME=&quot;nodejs&quot; at bundle time, so next/og always resolves the Node entry, even inside a worker. The workaround is sniffing the runtime myself and importing the edge build directly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const { ImageResponse } = (await (globalThis.navigator?.userAgent === 'Cloudflare-Workers'

  ? import(/* webpackIgnore: true */ 'next/dist/compiled/@vercel/og/index.edge.js')

  : import('next/og'))) as { ImageResponse: typeof ImageResponseType }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Navigator.userAgent === 'Cloudflare-Workers' is genuinely how you detect workerd. The webpackIgnore comment keeps webpack from trying to bundle the path at build time, and I pin the whole @vercel/og compiled directory into the output via outputFileTracingIncludes in next.config.ts so the edge build and its resvg wasm actually ship.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gotcha 3: fs reads land in the wrong directory&lt;/strong&gt;&lt;br&gt;
My OG route also reads custom fonts and a fallback backdrop off disk with readFile(path.join(process.cwd(), 'public', ...)). On Vercel, process.cwd() is the project root. On workerd, the vfs cwd is /bundle (the .open-next output root), so public/fonts doesn't exist where the code looks for it.&lt;/p&gt;
&lt;p&gt;The fix is a three-part move: the postbuild script copies public/fonts and backdrop_fallback.jpg into .open-next/public/, and wrangler's find_additional_modules + the Data rules in wrangler.jsonc ship those files in the worker's virtual filesystem. Same code path; files just exist where the worker looks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gotcha 4: packages hiding behind the workerd export condition&lt;/strong&gt;&lt;br&gt;
Some packages, in my case @emotion/* (Chakra's styling engine) and uncrypto, publish their ESM builds behind a workerd export condition. Next's file tracer only follows the CJS variants, so the worker bundle ends up with nothing it can resolve for those imports.&lt;/p&gt;
&lt;p&gt;The fix is listing them in serverExternalPackages in next.config.ts, which tells the adapter to copy the packages whole instead of relying on tracing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;serverExternalPackages: [

  '@emotion/react', '@emotion/cache', '@emotion/serialize',

  '@emotion/sheet', '@emotion/weak-memoize', '@emotion/hash',

  '@emotion/memoize', '@emotion/unitless', '@emotion/utils',

  '@emotion/use-insertion-effect-with-fallbacks',

  'hoist-non-react-statics', 'uncrypto'

]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you hit &quot;cannot resolve module&quot; errors on workerd that don't reproduce locally, this is the first thing to check.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gotcha 5: Vercel crons don't exist on Workers&lt;/strong&gt;&lt;br&gt;
vercel.json crons are a Vercel platform feature; nothing in a Next.js build output describes them. On Workers, the equivalent is triggers.crons + a scheduled() handler. But the adapter generates worker.js, so I wrap it in a custom entry that adds the handler and maps each cron expression back to the same endpoint Vercel used to hit:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// .open-next/entry.js, written by the postbuild script

import worker from './worker.js'

const CRON_ROUTES = {

  '0 6 * * *': '/api/cron/generate-content',

  '30 6 * * *': '/api/cron/streaming-changes',

  '0 7 * * *': '/api/cron/watchlist-alerts',

  '0 16 * * 5': '/api/cron/weekly-digest'

}

export default {

  ...worker,

  async scheduled(event, env, ctx) {

    const route = CRON_ROUTES[event.cron]

    if (!route) return

    ctx.waitUntil(

      env.WORKER_SELF_REFERENCE.fetch(

        new Request('https://worker.internal' + route, {

          headers: { authorization: 'Bearer ' + env.CRON_SECRET }

        })

      )

    )

  }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two things make this nice. The WORKER_SELF_REFERENCE service binding lets the worker call itself as an internal fetch, no public round trip. And the endpoints needed zero changes: they already checked Authorization: Bearer $CRON_SECRET because that's how Vercel's cron caller authenticates too. Testing is wrangler dev --test-scheduled, then hit /__scheduled?cron=0 6 &lt;em&gt; &lt;/em&gt; *.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Secrets&lt;/strong&gt;&lt;br&gt;
wrangler secret bulk takes a JSON file, so a 20-line script converts .env.local into .secrets.json, skipping NEXT&lt;em&gt;PUBLIC&lt;/em&gt;* vars (those get inlined at build time anyway) and my local Cloudflare API token. npm run cf:secrets and done: no dashboard clicking through a dozen vars.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cutover and rollback&lt;/strong&gt;&lt;br&gt;
The safest part of the whole migration was the cutover itself, because I deliberately ran both platforms in parallel:&lt;/p&gt;
&lt;p&gt;npm run cf:deploy, then verify everything on the *.workers.dev URL (all routes, OG images, cron triggers registered).&lt;br&gt;
Attach the galaxymovies.app + www custom domains to the worker. Since DNS was already on Cloudflare, this was instant, no propagation wait.&lt;br&gt;
Keep Vercel as cold standby: git.deploymentEnabled.main: false in vercel.json stops main pushes from auto-deploying, and I disabled the Vercel crons in the dashboard so the two platforms don't double-fire jobs.&lt;/p&gt;
&lt;p&gt;Rollback is re-adding two DNS records (A to Vercel's anycast IP, CNAME www to the Vercel DNS name). Traffic flips back immediately because the worker custom domains only take precedence while they're the only records on those names. That escape hatch made the whole thing low-stress: worst case is a DNS edit, not a redeploy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What's actually running&lt;/strong&gt;&lt;br&gt;
Same codebase, same next build, no platform fork in the source. SSR, ISR (backed by R2), all API routes, the OG image route, and all four crons work identically to how they did on Vercel. The only code that knows which platform it's on is that one navigator.userAgent check in the OG route.&lt;/p&gt;
&lt;p&gt;The honest summary: the adapter gets you ~80% there out of the box, and the remaining 20% is the kind of platform-shim work above. It's tractable, but expect an afternoon of debugging, not a lunch break. If your app leans on Node APIs that aren't fetch-shaped, the logic is different. But if you're already edge-friendly and your DNS is on Cloudflare anyway, the economics are hard to argue with, and Vercel sitting dormant as a free rollback target is a pretty nice safety net.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Repo notes worth taking if you're doing this: patch-package for the adapter externals, a postbuild script for stubs + vfs assets + the cron entry, serverExternalPackages for workerd-conditioned packages, and wrangler dev --test-scheduled for cron testing.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Happy to answer questions in the comments!&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/31124/vercel-was-too-expensive-so-i-migrated-my-next-js-app-to-cloudflare-workers</guid>
<pubDate>Thu, 15 Oct 2026 00:06:44 +0000</pubDate>
</item>
<item>
<title>Is Vercel Speed Insights enough for Core Web Vitals monitoring?</title>
<link>https://coderlegion.com/29700/is-vercel-speed-insights-enough-for-core-web-vitals-monitoring</link>
<description>&lt;p&gt;Strong first-party RUM on Vercel projects. Not a multi-client PageSpeed portfolio. Here is when it is enough, and when it is not.&lt;/p&gt;
&lt;p&gt;Agencies often turn on Vercel Speed Insights for a Next.js client, see route-level Core Web Vitals, and assume monitoring is “done.” For that Vercel project, the product is genuinely useful. For a book of WordPress, Shopify, Magento, and mixed hosts, it is not enough. Core Web Vitals monitoring means knowing when Largest Contentful Paint, Interaction to Next Paint, or Cumulative Layout Shift moves on the URLs you promised to watch. Host RUM answers that for instrumented Vercel deployments. It does not schedule lab checks across thirty other origins or give you one organisation view for account leads.&lt;/p&gt;
&lt;p&gt;What follows draws a clean line: when Speed Insights is enough, when you still need PageSpeed Insights field (Chrome UX Report) and scheduled lab coverage, and how agencies usually split the stack. For the synthetic-versus-field vocabulary, see &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=is-vercel-speed-insights-enough-core-web-vitals-monitoring&quot;&gt;When to Use Synthetic vs Real User Monitoring&lt;/a&gt;. For how agencies assemble DIY, portfolio, and RUM-plus-monitor recipes, see &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/agency-pagespeed-stacks-2026?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=is-vercel-speed-insights-enough-core-web-vitals-monitoring&quot;&gt;3 Agency PageSpeed Stacks for 2026&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what-vercel-speed-insights-actually-measures&quot;&gt;What Vercel Speed Insights actually measures&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://vercel.com/docs/speed-insights&quot;&gt;Vercel’s Speed Insights&lt;/a&gt; is first-party real-user monitoring for projects on Vercel. It collects Core Web Vitals and related timings from visitors on your deployed previews and production. The dashboard supports filters by route, device, time range, and (on paid Speed Insights tiers) richer breakdowns such as element-level views and geography. Vercel also stresses shorter windows than Google’s typical 28-day Chrome UX Report aggregation, which helps engineering see the effect of a deploy sooner.&lt;/p&gt;
&lt;p&gt;That is RUM scoped to the Vercel runtime and their collector. It is not Lighthouse. It is not a cold lab load from Google’s PageSpeed Insights workers. It is not a multi-tenant agency console for sites that never deploy to Vercel.&lt;/p&gt;
&lt;p&gt;Free and Plus packaging change how much detail you see (Vercel documents Real Experience Score on every plan, with fuller Core Web Vitals breakdowns on Plus). Pricing and feature gates move; treat the docs as source of truth for what your client’s plan includes.&lt;/p&gt;
&lt;h3 id=&quot;where-speed-insights-beats-pagespeed-insights-for-engineering&quot;&gt;Where Speed Insights beats PageSpeed Insights for engineering&lt;/h3&gt;
&lt;p&gt;PageSpeed Insights field data is Chrome UX Report: Chrome users, eligibility thresholds, origin or URL when sample size allows, rolling roughly 28-day window. That dataset matters for SEO conversations because it aligns with what Google publishes for page experience. It is a poor day-to-day triage tool when you need “which route broke after yesterday’s merge?”&lt;/p&gt;
&lt;p&gt;Speed Insights wins for Vercel engineering when you need:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Route-level RUM&lt;/strong&gt; on your own traffic, including browsers CrUX undersamples.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Faster iteration windows&lt;/strong&gt; after a deploy or branch, instead of waiting on a long CrUX lag.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Attribution&lt;/strong&gt; that names routes (and, on higher tiers, elements) instead of a single origin badge.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Vercel’s own Core Web Vitals guides make the same split: use CrUX / PageSpeed Insights field for the SEO-facing view; use Speed Insights (or another RUM path) for engineering triage on the Vercel app. Treat those as complementary field sources, not substitutes.&lt;/p&gt;
&lt;h3 id=&quot;where-it-is-not-enough-for-agency-portfolios&quot;&gt;Where it is not enough for agency portfolios&lt;/h3&gt;
&lt;p&gt;Agencies fail when they generalise from one Vercel client to the whole book.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hosts that are not on Vercel.&lt;/strong&gt; Most retained sites still run on WordPress hosts, Shopify, Magento, static elsewhere, or custom VPS stacks. Speed Insights does not cover those origins. You still need scheduled lab tests (PageSpeed Insights API / Lighthouse-class runs), CrUX where published, and a place to store history per client organisation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No shared multi-tenant workflow.&lt;/strong&gt; Account leads need one login, roles, budgets, alerts, and client-ready reports across many domains. A Vercel project dashboard per deployment is the wrong primitive for that job.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lab diagnosis still matters.&lt;/strong&gt; RUM tells you users felt a regression. Lab (and PageSpeed Insights opportunities) still help engineers reproduce LCP and CLS causes on a cold load. Speed Insights does not replace that diagnostic loop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CrUX remains the SEO reference.&lt;/strong&gt; When a sponsor asks “what does Google show?”, answer with Search Console or PageSpeed Insights field / CrUX, not only your first-party RUM chart. The two can disagree (browser mix, window length, URL versus origin). Label both.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enough when:&lt;/strong&gt; the engagement is one Vercel-hosted product, engineering owns the Vercel dashboard, and you only promise route-level RUM plus occasional CrUX checks for SEO.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Not enough when:&lt;/strong&gt; you sell portfolio monitoring across many client hosts, need discovery and schedules without a snippet on every domain, or need white-label reporting for non-Vercel properties.&lt;/p&gt;
&lt;h3 id=&quot;a-practical-stack-split&quot;&gt;A practical stack split&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Job &lt;/th&gt;&lt;th&gt;Prefer&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Route RUM on a Vercel Next.js app &lt;/td&gt;&lt;td&gt;Vercel Speed Insights (or equivalent first-party RUM)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SEO-facing field categories &lt;/td&gt;&lt;td&gt;CrUX via Search Console / PageSpeed Insights field&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Cold-load lab + opportunity text &lt;/td&gt;&lt;td&gt;PageSpeed Insights lab or scheduled PSI-style monitoring&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Many client sites, one org, budgets/alerts &lt;/td&gt;&lt;td&gt;Multi-tenant portfolio monitor (see the agency stack recipes linked above)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A common agency pattern: keep Speed Insights on the Vercel flagship; put scheduled lab-plus-CrUX monitoring on the rest of the portfolio; use CrUX as the shared SEO language in retainer packs. That matches the “RUM + monitor” stack idea without pretending one product covers every host.&lt;/p&gt;
&lt;p&gt;Do not disable Speed Insights to “avoid duplicate tools.” Duplicate tools are fine when they answer different questions. Duplicate &lt;em&gt;unlabelled&lt;/em&gt; numbers in a client PDF are not.&lt;/p&gt;
&lt;h3 id=&quot;faq&quot;&gt;FAQ&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Does Speed Insights replace PageSpeed Insights?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;No. Use Speed Insights for Vercel RUM triage. Use PageSpeed Insights (or Search Console) when you need CrUX-aligned field categories and lab diagnostics on a public URL.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can I rely on Speed Insights alone for SEO?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Risky. Google’s published field story is CrUX. First-party RUM helps you ship fixes faster; it is not the same dataset Search Console shows.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What if only one of twenty clients is on Vercel?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Instrument that one with Speed Insights. Monitor the other nineteen with a host-agnostic schedule. Do not wait for every client to migrate to Vercel before you watch regressions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is free Speed Insights “enough”?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Enough for a basic Real Experience Score on a Vercel project may be. Enough for element-level and geographic triage depends on the paid tier your client enables. Check Vercel’s current plan matrix before you promise those views in a retainer.&lt;/p&gt;
&lt;h3 id=&quot;what-to-do-next&quot;&gt;What to do next&lt;/h3&gt;
&lt;p&gt;List every production origin on the retainer. Mark which ones deploy on Vercel. Turn on Speed Insights (and the right paid tier) only where the runtime supports it. For every other origin, pick a scheduled lab-plus-CrUX path and write budgets in the same units you already use in client reviews. Put both field sources in the pack with labels: “Vercel RUM (this app)” versus “CrUX / PageSpeed Insights field (SEO window).”&lt;/p&gt;
&lt;p&gt;If you are choosing the portfolio half of the stack, start from the three recipes in &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/agency-pagespeed-stacks-2026?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=is-vercel-speed-insights-enough-core-web-vitals-monitoring&quot;&gt;3 Agency PageSpeed Stacks for 2026&lt;/a&gt; and the lab-versus-RUM framing in &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance?utm_source=hashnode&amp;amp;utm_medium=referral&amp;amp;utm_campaign=is-vercel-speed-insights-enough-core-web-vitals-monitoring&quot;&gt;When to Use Synthetic vs Real User Monitoring&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://vercel.com/docs/speed-insights&quot;&gt;Speed Insights Overview&lt;/a&gt; (Vercel docs)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://vercel.com/kb/guide/how-to-improve-core-web-vitals&quot;&gt;How to improve Core Web Vitals&lt;/a&gt; (Vercel)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://vercel.com/blog/how-core-web-vitals-affect-seo&quot;&gt;How Core Web Vitals affect SEO&lt;/a&gt; (Vercel)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/agency-pagespeed-stacks-2026&quot;&gt;3 Agency PageSpeed Stacks for 2026&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/when-to-use-synthetic-vs-real-user-monitoring-performance&quot;&gt;When to Use Synthetic vs Real User Monitoring for Performance&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a rel=&quot;nofollow&quot; href=&quot;https://devlog.apogeewatcher.com/is-vercel-speed-insights-enough-core-web-vitals-monitoring&quot;&gt;Hashnode&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/29700/is-vercel-speed-insights-enough-for-core-web-vitals-monitoring</guid>
<pubDate>Sun, 04 Oct 2026 06:55:01 +0000</pubDate>
</item>
<item>
<title>From Static Page to Evidence-Aware Knowledge Explorer: What We Implemented in MyZubster</title>
<link>https://coderlegion.com/28261/from-static-page-to-evidence-aware-knowledge-explorer-what-we-implemented-in-myzubster</link>
<description>&lt;h2 id=&quot;from-static-page-to-evidence-aware-knowledge-explorer-what-we-implemented-in-myzubster&quot;&gt;From Static Page to Evidence-Aware Knowledge Explorer: What We Implemented in MyZubster&lt;/h2&gt;
&lt;p&gt;MyZubster Knowledge Explorer started as a static page listing domains and canonical records.&lt;/p&gt;
&lt;p&gt;The content was useful, but the interaction model was too flat: domains, records, evidence states and details all competed for attention in one page.&lt;/p&gt;
&lt;p&gt;We rebuilt the explorer as a lightweight, evidence-aware static interface and deployed it to Vercel.&lt;/p&gt;
&lt;p&gt;Live page:&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://myzubster-knowledge-myzubster.vercel.app/knowledge.html&quot;&gt;https://myzubster-knowledge-myzubster.vercel.app/knowledge.html&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;the-implementation&quot;&gt;The implementation&lt;/h3&gt;
&lt;p&gt;The deployment remains intentionally simple:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;public/
└── knowledge.html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No framework runtime. No additional backend. No database migration.&lt;/p&gt;
&lt;p&gt;The page contains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;responsive CSS;&lt;/li&gt;
&lt;li&gt;a client-side record registry;&lt;/li&gt;
&lt;li&gt;dynamic domain navigation;&lt;/li&gt;
&lt;li&gt;full-text search;&lt;/li&gt;
&lt;li&gt;evidence-state filtering;&lt;/li&gt;
&lt;li&gt;selectable record cards;&lt;/li&gt;
&lt;li&gt;an inline detail panel.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The record model is minimal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;{
  id: &quot;MZ-001&quot;,
  title: &quot;Knowledge Layer — canonical record protocol&quot;,
  domain: &quot;MyZubster&quot;,
  state: &quot;PROTOCOL&quot;,
  description: &quot;Defines the Knowledge Explorer as a catalogue of traceable records...&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is enough to make records searchable, classifiable and inspectable without pretending that the UI is already a full verification system.&lt;/p&gt;
&lt;h3 id=&quot;evidence-states-are-part-of-the-data-model&quot;&gt;Evidence states are part of the data model&lt;/h3&gt;
&lt;p&gt;The key decision was to make evidence classification explicit:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;PERSONAL_PRACTICE
OBSERVATION
EXTERNAL_SOURCE
PROTOCOL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These are not visual tags only.&lt;/p&gt;
&lt;p&gt;They communicate what a record is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a first-hand practice;&lt;/li&gt;
&lt;li&gt;a documented observation;&lt;/li&gt;
&lt;li&gt;an identifiable external source;&lt;/li&gt;
&lt;li&gt;or a proposed protocol.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A record can be useful without being verified guidance.&lt;/p&gt;
&lt;p&gt;That distinction is essential when the catalogue includes technical workflows, community practices, circular-economy proposals and health-adjacent product knowledge.&lt;/p&gt;
&lt;h3 id=&quot;filtering-records&quot;&gt;Filtering records&lt;/h3&gt;
&lt;p&gt;The page combines domain selection, evidence state and text search in one filtering function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const list = records.filter((record) =&amp;gt;
  (active === &quot;All&quot; || record.domain === active) &amp;amp;&amp;amp;
  (!state || record.state === state) &amp;amp;&amp;amp;
  `${record.id} ${record.title} ${record.domain} ${record.description}`
    .toLowerCase()
    .includes(query)
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This keeps the first version dependency-free and deterministic.&lt;/p&gt;
&lt;p&gt;For a small catalogue, a client-side array is enough. For a larger knowledge base, the next step is build-time index generation from versioned source files.&lt;/p&gt;
&lt;h3 id=&quot;new-myzubster-protocol-records&quot;&gt;New MyZubster protocol records&lt;/h3&gt;
&lt;p&gt;We introduced a dedicated MyZubster domain:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;MZ-001 — Knowledge Layer — canonical record protocol
MZ-002 — Evidence states — from collection to independent review
MZ-003 — Zorgax — AI assistance with human verification
MZ-004 — Development requests — turning patterns into testable work
MZ-005 — Circular economies — verified contribution model
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These records capture the architecture behind the project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI assists with retrieval, structure and connections;&lt;/li&gt;
&lt;li&gt;AI does not determine truth;&lt;/li&gt;
&lt;li&gt;data integrity is not the same as scientific validity;&lt;/li&gt;
&lt;li&gt;observed patterns can become scoped development requests;&lt;/li&gt;
&lt;li&gt;digital evidence alone does not prove a physical-world outcome.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;circular-economies-and-absorbent-product-knowledge&quot;&gt;Circular economies and absorbent-product knowledge&lt;/h3&gt;
&lt;p&gt;We also added a new &lt;code&gt;Circular economies&lt;/code&gt; domain:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;AHP-001 — Circular Hygiene — evidence pilot framework
AHP-002 — Absorbent-product experience contribution model
AHP-003 — Absorbent materials — test and traceability template
AHP-004 — Circular economies — reproducible pilot catalogue
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All are marked &lt;code&gt;PROTOCOL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is intentional. They define ways to collect observations, trace materials and structure future tests. They do not claim that recycling performance, safety, comfort or environmental impact has already been independently validated.&lt;/p&gt;
&lt;p&gt;A possible contribution path looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;lived experience
→ documented observation
→ repeated pattern
→ DevelopmentRequest
→ prototype or research task
→ independent review
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The important part is the boundary: user experience can guide product development without being misrepresented as clinical or scientific proof.&lt;/p&gt;
&lt;h3 id=&quot;deployment-and-validation&quot;&gt;Deployment and validation&lt;/h3&gt;
&lt;p&gt;Before deployment, we checked the static JavaScript syntax:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;node -e '
const fs = require(&quot;fs&quot;);
const source = fs.readFileSync(&quot;public/knowledge.html&quot;, &quot;utf8&quot;);
const script = source.match(/&amp;lt;script&amp;gt;([\s\S]*?)&amp;lt;\/script&amp;gt;/)[1];
new Function(script);
console.log(&quot;JavaScript valid&quot;);
'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We then confirmed that the new canonical IDs existed in the file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;grep -n &quot;MZ-001\|AHP-001\|Circular economies&quot; public/knowledge.html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we created a timestamped backup and deployed through the existing Vercel project:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cp public/knowledge.html \
  &quot;public/knowledge.html.bak.$(date +%F-%H%M%S)&quot;

vercel --prod --yes --scope myzubster
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;what-comes-next&quot;&gt;What comes next&lt;/h3&gt;
&lt;p&gt;The current implementation is a practical static layer. The next technical steps are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;move records to Markdown files with YAML front matter;&lt;/li&gt;
&lt;li&gt;validate record schemas in CI;&lt;/li&gt;
&lt;li&gt;generate the domain index at build time;&lt;/li&gt;
&lt;li&gt;add stable routes for individual records;&lt;/li&gt;
&lt;li&gt;link records to sources, evidence and Development Requests;&lt;/li&gt;
&lt;li&gt;add consent-aware contribution flows;&lt;/li&gt;
&lt;li&gt;add independent review before any record is promoted to verified guidance.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;final-thought&quot;&gt;Final thought&lt;/h3&gt;
&lt;p&gt;The goal is not to build another content directory.&lt;/p&gt;
&lt;p&gt;The goal is to build a knowledge interface where uncertainty is visible, evidence is classified and contributions can evolve into testable work.&lt;/p&gt;
&lt;p&gt;A static page is only the first layer. The real architecture is the discipline of not confusing a claim, an observation, an AI summary and a verified result.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/28261/from-static-page-to-evidence-aware-knowledge-explorer-what-we-implemented-in-myzubster</guid>
<pubDate>Wed, 23 Sep 2026 05:23:18 +0000</pubDate>
</item>
<item>
<title>Building Zorgax in Production: Hybrid AI Routing, Grounding, Fallbacks, and UX</title>
<link>https://coderlegion.com/27648/building-zorgax-in-production-hybrid-ai-routing-grounding-fallbacks-and-ux</link>
<description>&lt;p&gt;Building Zorgax in Production: Hybrid AI Routing, Grounding, Fallbacks, and UX&lt;/p&gt;
&lt;p&gt;Building an AI chatbot is easy.&lt;/p&gt;
&lt;p&gt;Building an AI feature that survives production is a very different problem.&lt;/p&gt;
&lt;p&gt;Over the last development cycle, we evolved Zorgax, the AI copilot inside MyZubster, from a simple conversational interface into a hybrid AI layer with model routing, cost controls, fallback logic, product grounding, runtime observability, and tighter integration with the rest of the platform.&lt;/p&gt;
&lt;p&gt;The most interesting lesson was that the LLM API call ended up being one of the smallest parts of the system.&lt;/p&gt;
&lt;p&gt;The goal&lt;/p&gt;
&lt;p&gt;Zorgax is designed to act as the conversational entry point to MyZubster.&lt;/p&gt;
&lt;p&gt;A user should be able to ask a normal question, explore the Marketplace, understand a LIFE Pilot, start a Seller journey, navigate the Metaverse, or receive guidance about the wider ecosystem.&lt;/p&gt;
&lt;p&gt;But we did not want every request to go through the same AI model.&lt;/p&gt;
&lt;p&gt;A simple message such as:&lt;/p&gt;
&lt;p&gt;Ciao Zorgax&lt;/p&gt;
&lt;p&gt;does not need the same infrastructure as:&lt;/p&gt;
&lt;p&gt;Analyze the current LIFE workflow, evaluate KPI/MRV evidence,&lt;br&gt;
and explain the deployment and repository architecture.&lt;/p&gt;
&lt;p&gt;So we introduced a routing layer.&lt;/p&gt;
&lt;p&gt;Hybrid model routing&lt;/p&gt;
&lt;p&gt;The current architecture separates requests into broad standard and complex categories.&lt;/p&gt;
&lt;p&gt;Research mode, long prompts, and signals related to coding, deployment, research, LIFE, KPI/MRV, automation, GitHub, or Vercel can move a request into the complex route.&lt;/p&gt;
&lt;p&gt;Conceptually:&lt;/p&gt;
&lt;p&gt;const tier =&lt;br&gt;
  useResearch ||&lt;br&gt;
  complexSignalCount &amp;gt;= 2 ||&lt;br&gt;
  text.length &amp;gt;= 2500&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;? &quot;complex&quot;
: &quot;standard&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The architecture then becomes:&lt;/p&gt;
&lt;p&gt;User&lt;br&gt;
  ↓&lt;br&gt;
Zorgax API&lt;br&gt;
  ↓&lt;br&gt;
Task classification&lt;br&gt;
  ↓&lt;br&gt;
AI Router&lt;br&gt;
  ├── Standard → Ollama / general AI gateway&lt;br&gt;
  │&lt;br&gt;
  └── Complex / Research → OpenAI&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                        ↓
                     fallback
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This gives us a hybrid system instead of making the whole product dependent on one remote provider.&lt;/p&gt;
&lt;p&gt;Making the model visible&lt;/p&gt;
&lt;p&gt;One of the first improvements was exposing the actual route used by the backend.&lt;/p&gt;
&lt;p&gt;The API returns metadata like:&lt;/p&gt;
&lt;p&gt;{&lt;br&gt;
  &quot;ai_provider&quot;: &quot;openai&quot;,&lt;br&gt;
  &quot;ai_model&quot;: &quot;gpt-5.6-sol&quot;,&lt;br&gt;
  &quot;ai_fallback_reason&quot;: null&lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;The interface displays it directly below the response:&lt;/p&gt;
&lt;p&gt;AI: OpenAI · gpt-5.6-sol&lt;/p&gt;
&lt;p&gt;If something goes wrong:&lt;/p&gt;
&lt;p&gt;AI: Ollama · qwen2.5:3b · fallback: openai_rate_limit&lt;/p&gt;
&lt;p&gt;This looks like a small UI feature, but operationally it changes a lot.&lt;/p&gt;
&lt;p&gt;We no longer have to ask:&lt;/p&gt;
&lt;p&gt;Did OpenAI actually generate this answer?&lt;/p&gt;
&lt;p&gt;The application tells us.&lt;/p&gt;
&lt;p&gt;The first production surprise&lt;/p&gt;
&lt;p&gt;Once OpenAI routing was enabled, the first production request did not succeed.&lt;/p&gt;
&lt;p&gt;Zorgax returned a valid answer, but the logs showed:&lt;/p&gt;
&lt;p&gt;aiProvider: ollama&lt;br&gt;
aiModel: qwen2.5:3b&lt;br&gt;
aiFallbackReason: openai_error&lt;/p&gt;
&lt;p&gt;The OpenAI call had returned HTTP 429.&lt;/p&gt;
&lt;p&gt;At first, that was not enough information.&lt;/p&gt;
&lt;p&gt;A 429 can represent very different conditions: a temporary rate limit, exhausted API credits, a project spending limit, or another usage restriction.&lt;/p&gt;
&lt;p&gt;So we improved the error handling rather than simply retrying blindly.&lt;/p&gt;
&lt;p&gt;Precise OpenAI diagnostics&lt;/p&gt;
&lt;p&gt;Zorgax now extracts safe diagnostic information from failed requests:&lt;/p&gt;
&lt;p&gt;HTTP status&lt;br&gt;
error code&lt;br&gt;
error type&lt;br&gt;
request id&lt;/p&gt;
&lt;p&gt;without exposing credentials.&lt;/p&gt;
&lt;p&gt;Fallback states can now be much more precise:&lt;/p&gt;
&lt;p&gt;openai_credit_balance_exhausted&lt;br&gt;
openai_rate_limit&lt;br&gt;
openai_rate_limit_exceeded&lt;br&gt;
openai_project_spend_limit_exceeded&lt;/p&gt;
&lt;p&gt;That immediately paid off.&lt;/p&gt;
&lt;p&gt;Our next production test returned:&lt;/p&gt;
&lt;p&gt;openai_credit_balance_exhausted&lt;/p&gt;
&lt;p&gt;The application was working correctly. The account simply had no API credit.&lt;/p&gt;
&lt;p&gt;After adding credit, the next request succeeded with:&lt;/p&gt;
&lt;p&gt;AI: OpenAI · gpt-5.6-sol&lt;/p&gt;
&lt;p&gt;and production logs confirmed:&lt;/p&gt;
&lt;p&gt;aiProvider: openai&lt;br&gt;
aiModel: gpt-5.6-sol&lt;br&gt;
aiFallbackReason: null&lt;/p&gt;
&lt;p&gt;That was the first full end-to-end verification.&lt;/p&gt;
&lt;p&gt;Retry without retrying everything forever&lt;/p&gt;
&lt;p&gt;Transient failures still need resilience.&lt;/p&gt;
&lt;p&gt;For rate-limit-style failures, Zorgax now has controlled retry behavior.&lt;/p&gt;
&lt;p&gt;The primary route can retry once, respecting Retry-After when the wait is short enough. A secondary OpenAI model can then be attempted before the system falls back to the local/general route.&lt;/p&gt;
&lt;p&gt;The flow is roughly:&lt;/p&gt;
&lt;p&gt;gpt-5.6-sol&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; ↓
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;controlled retry&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; ↓
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;secondary OpenAI model&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; ↓
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ollama fallback&lt;/p&gt;
&lt;p&gt;Quota errors are different.&lt;/p&gt;
&lt;p&gt;If the API explicitly says credits are exhausted, retrying repeatedly would only waste time, so the fallback happens immediately.&lt;/p&gt;
&lt;p&gt;That distinction is important: resilience does not mean retrying every failure.&lt;/p&gt;
&lt;p&gt;Cost controls belong in the architecture&lt;/p&gt;
&lt;p&gt;Remote AI usage also needs application-level cost controls.&lt;/p&gt;
&lt;p&gt;Before sending a complex request, Zorgax checks its monthly OpenAI budget and reserves enough capacity for the request.&lt;/p&gt;
&lt;p&gt;The flow looks like this:&lt;/p&gt;
&lt;p&gt;Classify request&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  ↓
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check monthly spend&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  ↓
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Estimate request cost&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  ↓
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reserve budget&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  ↓
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Call OpenAI&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  ↓
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Record actual usage&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  ↓
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Settle reservation&lt;/p&gt;
&lt;p&gt;If the reservation cannot be made, the conversation can continue through the fallback path.&lt;/p&gt;
&lt;p&gt;We also record the model that actually completed the request, so usage accounting still makes sense if a secondary OpenAI model is used.&lt;/p&gt;
&lt;p&gt;Grounding became the harder problem&lt;/p&gt;
&lt;p&gt;Once OpenAI was running correctly, another issue appeared.&lt;/p&gt;
&lt;p&gt;The model became too conservative.&lt;/p&gt;
&lt;p&gt;We asked Zorgax which MyZubster features were live, experimental, planned, or unverified.&lt;/p&gt;
&lt;p&gt;The answer classified nearly everything as unverified.&lt;/p&gt;
&lt;p&gt;That was technically cautious, but it was also wrong.&lt;/p&gt;
&lt;p&gt;The reason was architectural: the OpenAI route and the Ollama route were not receiving exactly the same runtime product context.&lt;/p&gt;
&lt;p&gt;The local route had product facts.&lt;/p&gt;
&lt;p&gt;The OpenAI route mostly had the system persona and the user message.&lt;/p&gt;
&lt;p&gt;So instead of weakening our anti-hallucination rules, we fixed the input architecture.&lt;/p&gt;
&lt;p&gt;One canonical runtime context&lt;/p&gt;
&lt;p&gt;Both model paths now receive the same canonical product context.&lt;/p&gt;
&lt;p&gt;It includes facts such as:&lt;/p&gt;
&lt;p&gt;myzubster.com is live&lt;/p&gt;
&lt;p&gt;/marketplace is an implemented route&lt;/p&gt;
&lt;p&gt;Seller starts from Marketplace&lt;/p&gt;
&lt;p&gt;/social-login is the authentication path&lt;/p&gt;
&lt;p&gt;/metaverse is an implemented route&lt;/p&gt;
&lt;p&gt;/life-pilot is an implemented pilot path&lt;/p&gt;
&lt;p&gt;MYZ is internal reward/accounting&lt;/p&gt;
&lt;p&gt;It also contains an important rule:&lt;/p&gt;
&lt;p&gt;A live route does not prove every possible feature associated with that route.&lt;/p&gt;
&lt;p&gt;That distinction prevents two opposite failures.&lt;/p&gt;
&lt;p&gt;The assistant should not invent features that do not exist, but it should also not deny the existence of routes that are actually implemented.&lt;/p&gt;
&lt;p&gt;Product state as part of the prompt&lt;/p&gt;
&lt;p&gt;Zorgax now reasons with four capability states:&lt;/p&gt;
&lt;p&gt;LIVE / IMPLEMENTED&lt;br&gt;
PILOT / EXPERIMENTAL&lt;br&gt;
PROPOSED / PLANNED&lt;br&gt;
UNKNOWN / UNVERIFIED&lt;/p&gt;
&lt;p&gt;For example, /metaverse being live means the route exists.&lt;/p&gt;
&lt;p&gt;It does not automatically mean Sellers can create virtual stores.&lt;/p&gt;
&lt;p&gt;Likewise, /life-pilot being live does not prove that GPS field reporting, scientific validation, public map publication, or environmental measurements are all implemented.&lt;/p&gt;
&lt;p&gt;After introducing the shared runtime context, the same test produced a much better result.&lt;/p&gt;
&lt;p&gt;Marketplace, Seller flow, authentication, Metaverse, LIFE Pilot, open-source contribution, and MYZ were described according to their verified status, while advanced dashboards, IoT integrations, IPFS/IPNS workflows, and external settlement remained unverified.&lt;/p&gt;
&lt;p&gt;And this time the answer was generated by:&lt;/p&gt;
&lt;p&gt;AI: OpenAI · gpt-5.6-sol&lt;br&gt;
The chat itself needed work too&lt;/p&gt;
&lt;p&gt;Backend architecture was only half the problem.&lt;/p&gt;
&lt;p&gt;The original Zorgax interface had a very small conversation area.&lt;/p&gt;
&lt;p&gt;Long AI answers appeared with the scroll position close to the end of the response, forcing the user to scroll upward to begin reading.&lt;/p&gt;
&lt;p&gt;We changed the page so that the conversation became the main content area.&lt;/p&gt;
&lt;p&gt;New assistant replies are now positioned at the beginning of the new response rather than the end.&lt;/p&gt;
&lt;p&gt;The scroll logic is roughly:&lt;/p&gt;
&lt;p&gt;function scrollMessageToTop(element) {&lt;br&gt;
  const delta =&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;element.getBoundingClientRect().top -
messages.getBoundingClientRect().top;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  messages.scrollTo({&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;top: messages.scrollTop + delta - 12,
behavior: &quot;smooth&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  });&lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;We also prevent textarea focus from modifying the viewport:&lt;/p&gt;
&lt;p&gt;input.focus({ preventScroll: true });&lt;/p&gt;
&lt;p&gt;This made long-form AI responses dramatically easier to read.&lt;/p&gt;
&lt;p&gt;Zorgax also needed an exit&lt;/p&gt;
&lt;p&gt;There was one more product problem.&lt;/p&gt;
&lt;p&gt;Once a user entered Zorgax, the assistant page felt too isolated from the rest of MyZubster.&lt;/p&gt;
&lt;p&gt;A product copilot should help users move through the product, not trap them inside the AI interface.&lt;/p&gt;
&lt;p&gt;So we added permanent navigation in the Zorgax header:&lt;/p&gt;
&lt;p&gt;🏠 Home MyZubster&lt;br&gt;
🛒 Marketplace&lt;/p&gt;
&lt;p&gt;The page also contains guided actions for Seller, Marketplace, Metaverse, LIFE Pilot, University/research, Community, and other supported journeys.&lt;/p&gt;
&lt;p&gt;This turned Zorgax from a standalone AI page into a real navigation layer for the wider product.&lt;/p&gt;
&lt;p&gt;Observability closed the loop&lt;/p&gt;
&lt;p&gt;Vercel runtime logging now gives us a compact record of every AI routing decision.&lt;/p&gt;
&lt;p&gt;A successful production event can look like:&lt;/p&gt;
&lt;p&gt;event: zorgax_message_sent&lt;br&gt;
plan: pro&lt;br&gt;
webResearch: true&lt;br&gt;
sourceCount: 0&lt;br&gt;
aiProvider: openai&lt;br&gt;
aiModel: gpt-5.6-sol&lt;br&gt;
aiFallbackReason: null&lt;/p&gt;
&lt;p&gt;During debugging, this was one of the most valuable pieces of the system.&lt;/p&gt;
&lt;p&gt;Without it, an answer that looked fine could still have silently come from the fallback model.&lt;/p&gt;
&lt;p&gt;With it, we can trace the actual production path.&lt;/p&gt;
&lt;p&gt;What the architecture looks like now&lt;/p&gt;
&lt;p&gt;The current system can be summarized like this:&lt;/p&gt;
&lt;p&gt;User&lt;br&gt;
  ↓&lt;br&gt;
Zorgax UI&lt;br&gt;
  ↓&lt;br&gt;
Access policy&lt;br&gt;
  ↓&lt;br&gt;
Optional research&lt;br&gt;
  ↓&lt;br&gt;
Task classification&lt;br&gt;
  ↓&lt;br&gt;
Canonical product context&lt;br&gt;
  ↓&lt;br&gt;
AI Router&lt;br&gt;
  ├── OpenAI&lt;br&gt;
  │    ├── primary model&lt;br&gt;
  │    ├── controlled retry&lt;br&gt;
  │    └── secondary model&lt;br&gt;
  │&lt;br&gt;
  └── Ollama / general AI fallback&lt;br&gt;
  ↓&lt;br&gt;
Grounded answer&lt;br&gt;
  ↓&lt;br&gt;
Provider + model metadata&lt;br&gt;
  ↓&lt;br&gt;
Runtime logs&lt;br&gt;
  ↓&lt;br&gt;
User&lt;/p&gt;
&lt;p&gt;That is much closer to an AI product architecture than a simple chatbot.&lt;/p&gt;
&lt;p&gt;What we learned&lt;/p&gt;
&lt;p&gt;The LLM call was the easy part.&lt;/p&gt;
&lt;p&gt;The actual production system is:&lt;/p&gt;
&lt;p&gt;model&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;routing&lt;/li&gt;
&lt;li&gt;budget controls&lt;/li&gt;
&lt;li&gt;retry policy&lt;/li&gt;
&lt;li&gt;fallbacks&lt;/li&gt;
&lt;li&gt;grounding&lt;/li&gt;
&lt;li&gt;authorization&lt;/li&gt;
&lt;li&gt;observability&lt;/li&gt;
&lt;li&gt;UI&lt;/li&gt;
&lt;li&gt;navigation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The more capable an AI model becomes, the more important it is for the application around it to define what is real.&lt;/p&gt;
&lt;p&gt;The application has to know:&lt;/p&gt;
&lt;p&gt;what exists&lt;br&gt;
what is experimental&lt;br&gt;
what is verified&lt;br&gt;
what the AI may do&lt;br&gt;
what actually happened&lt;/p&gt;
&lt;p&gt;That is the direction we are taking with Zorgax and MyZubster.&lt;/p&gt;
&lt;p&gt;AI can reason.&lt;/p&gt;
&lt;p&gt;The product still owns truth, permissions, evidence, and execution.&lt;/p&gt;
&lt;p&gt;We did not come to conquer. We came to build together.&lt;/p&gt;
&lt;p&gt;Per CoderLegion userei come titolo:&lt;/p&gt;
&lt;p&gt;Building Zorgax in Production: Hybrid AI Routing, Grounding, Fallbacks, and UX&lt;/p&gt;
&lt;p&gt;Come sottotitolo:&lt;/p&gt;
&lt;p&gt;How we evolved the MyZubster assistant from a chat interface into an observable, budget-aware, multi-model product copilot.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/27648/building-zorgax-in-production-hybrid-ai-routing-grounding-fallbacks-and-ux</guid>
<pubDate>Fri, 18 Sep 2026 15:05:04 +0000</pubDate>
</item>
<item>
<title># Building a Serverless-Safe Realtime Metaverse for MyZubster</title>
<link>https://coderlegion.com/25979/building-a-serverless-safe-realtime-metaverse-for-myzubster</link>
<description>&lt;h2 id=&quot;building-a-serverless-safe-realtime-metaverse-for-myzubster&quot;&gt;Building a Serverless-Safe Realtime Metaverse for MyZubster&lt;/h2&gt;
&lt;p&gt;We have completed a major infrastructure upgrade for &lt;strong&gt;MyZubster World&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The original realtime system used Server-Sent Events and in-memory state. It worked locally, but serverless deployments introduced a problem: different requests could reach different Vercel instances, each with its own memory.&lt;/p&gt;
&lt;p&gt;The result? Players could join successfully while the interface remained stuck on &lt;code&gt;RECONNECTING&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what-we-changed&quot;&gt;What we changed&lt;/h3&gt;
&lt;p&gt;We moved the shared Metaverse state to MongoDB.&lt;/p&gt;
&lt;p&gt;The new architecture supports:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;shared player presence across serverless instances;&lt;/li&gt;
&lt;li&gt;synchronized movements and emotes;&lt;/li&gt;
&lt;li&gt;recent shared chat messages;&lt;/li&gt;
&lt;li&gt;automatic expiration of inactive sessions with TTL indexes;&lt;/li&gt;
&lt;li&gt;resilient browser synchronization;&lt;/li&gt;
&lt;li&gt;automatic recovery after temporary connection failures;&lt;/li&gt;
&lt;li&gt;verified MyZubster characters linked to authenticated accounts;&lt;/li&gt;
&lt;li&gt;clear separation between verified users and guests.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The React frontend now periodically calls:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;POST /api/metaverse/sync
Each synchronization refreshes the session and returns the current players, movements, emotes, and new chat messages.
This replaces the fragile dependency on a long-lived EventSource connection.
Verified identity
Authenticated users enter with the character linked by the server to their MyZubster account.
Browser-supplied names and identifiers cannot override a verified identity.
For example, the character H4x0r is displayed as:
H4x0r
@DanielIoni-creator
MYZ VERIFIED
Guests can still explore the world, but they are clearly marked as guests.
Production results
The implementation was successfully deployed and verified:
- Vercel deployment: ready;
- world API: HTTP 200;
- active transport: shared-polling;
- MongoDB shared presence: operational;
- legacy Metaverse EventSource removed from the frontend;
- 11 automated tests passed.
This architecture gives MyZubster a reliable serverless foundation today while keeping the door open for WebSockets, Redis, or a dedicated realtime network in the future.
Explore MyZubster World:
🌍 https://www.myzubster.com/metaverse
View the implementation:
💻 https://github.com/MyZubster-Ecosystem/myzubster/commit/412babfedfe29a917e5c6802c34defdcbfad75e7
What approach do you prefer for realtime serverless applications: polling, WebSockets, Redis streams, or an external realtime provider?
#MyZubster #OpenSource #Metaverse #ReactJS #NodeJS #MongoDB #Serverless #WebDevelopment #Realtime #Vercel
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/25979/building-a-serverless-safe-realtime-metaverse-for-myzubster</guid>
<pubDate>Tue, 01 Sep 2026 09:31:49 +0000</pubDate>
</item>
<item>
<title>How to Deploy Your Website for Free (Vercel, Netlify, GitHub Pages)</title>
<link>https://coderlegion.com/23002/how-to-deploy-your-website-for-free-vercel-netlify-github-pages</link>
<description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Building your first project is one milestone. Actually getting it live on the internet, with a real URL you can share, is a completely different feeling — and it used to be way more complicated than it is now.&lt;/p&gt;
&lt;p&gt;Today, deploying a frontend project is genuinely a 5-minute job with the right platform. Here are the three most beginner-friendly options and exactly how to use each one.&lt;/p&gt;
&lt;h2 id=&quot;option-1-vercel-best-for-react-next-js-projects-&quot;&gt;Option 1: Vercel (Best for React/Next.js Projects)&lt;/h2&gt;
&lt;p&gt;Vercel is built by the creators of Next.js, and it's my personal go-to for React projects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Push your project to a GitHub repository (see Article 7 if you need a refresher)&lt;/li&gt;
&lt;li&gt;Go to vercel.com and sign up with your GitHub account&lt;/li&gt;
&lt;li&gt;Click &quot;Add New Project&quot;&lt;/li&gt;
&lt;li&gt;Select your repository&lt;/li&gt;
&lt;li&gt;Vercel auto-detects your framework (React, Next.js, Vite, etc.) and sets the build settings  automatically&lt;/li&gt;
&lt;li&gt;Click &quot;Deploy&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That's it. Within a minute or two, you get a live URL like &lt;strong&gt;your-project.vercel.app&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bonus&lt;/strong&gt;: Every time you push new code to GitHub, Vercel automatically redeploys your site. No manual re-upload, ever.&lt;/p&gt;
&lt;h2 id=&quot;option-2-netlify-great-all-rounder-&quot;&gt;Option 2: Netlify (Great All-Rounder)&lt;/h2&gt;
&lt;p&gt;Netlify works almost identically to Vercel and is equally beginner-friendly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Push your project to GitHub&lt;/li&gt;
&lt;li&gt;Go to netlify.com and sign up with GitHub&lt;/li&gt;
&lt;li&gt;Click &quot;Add new site&quot; → &quot;Import an existing project&quot;&lt;/li&gt;
&lt;li&gt;Select your repository&lt;/li&gt;
&lt;li&gt;Set your build command (for a Vite React app, this is usually npm run build) and publish directory (dist)&lt;/li&gt;
&lt;li&gt;Click &quot;Deploy site&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You'll get a URL like &lt;strong&gt;your-project.netlify.app&lt;/strong&gt;, with the same automatic redeploy behavior on every push.&lt;/p&gt;
&lt;p&gt;Netlify extra: It has a built-in drag-and-drop deploy option too — for a plain HTML/CSS/JS site with no build step, you can literally drag your project folder into the browser and it goes live instantly.&lt;/p&gt;
&lt;h2 id=&quot;option-3-github-pages-simplest-for-static-sites-&quot;&gt;Option 3: GitHub Pages (Simplest for Static Sites)&lt;/h2&gt;
&lt;p&gt;GitHub Pages is a solid choice for portfolio sites and static HTML/CSS/JS projects — it's what many developers use for their own portfolio (mine included).&lt;/p&gt;
&lt;p&gt;Steps for a React (Vite) project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install the gh-pages package:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;npm install gh-pages --save-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;In package.json, add:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&quot;homepage&quot;: &quot;https://yourusername.github.io/your-repo-name&quot;,
&quot;scripts&quot;: {
  &quot;predeploy&quot;: &quot;npm run build&quot;,
  &quot;deploy&quot;: &quot;gh-pages -d dist&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Run:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;npm run deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;In your GitHub repo settings, go to Pages and confirm the source is set to the &lt;strong&gt;gh-pages&lt;/strong&gt; branch.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your site goes live at &lt;strong&gt;yourusername.github.io/your-repo-name.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For a plain HTML/CSS/JS project (no build step):&lt;/p&gt;
&lt;p&gt;Just push your files to GitHub, go to Settings → Pages, select your main branch as the source, and save. Done.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vercel — Best for React and Next.js projects. Offers a free custom domain.&lt;/li&gt;
&lt;li&gt;Netlify — Best for any frontend framework, with built-in form handling and serverless functions. Offers a free custom domain.&lt;/li&gt;
&lt;li&gt;GitHub Pages — Best for simple static websites and portfolios. Supports a free custom domain with a little setup.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;My honest recommendation:&lt;/strong&gt; use Vercel or Netlify for client and freelance projects — they handle builds, environment variables, and redeploys more smoothly. Use GitHub Pages for personal portfolio projects where simplicity matters more than advanced features.&lt;/p&gt;
&lt;h2 id=&quot;common-beginner-mistakes&quot;&gt;Common Beginner Mistakes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Forgetting to set the correct build/publish directory. For Vite projects, it's &lt;strong&gt;dist&lt;/strong&gt;. For Create React App, it's &lt;strong&gt;build&lt;/strong&gt;. Get this wrong and you'll see a blank page.&lt;/li&gt;
&lt;li&gt;Hardcoding API keys directly in your code instead of using environment variables — both Vercel and Netlify let you set these securely in project settings.&lt;/li&gt;
&lt;li&gt;Not testing the production build locally first. Run &lt;strong&gt;npm run build&lt;/strong&gt; and &lt;strong&gt;npm run preview&lt;/strong&gt; (Vite) before deploying, to catch build errors early.&lt;/li&gt;
&lt;li&gt;Forgetting the &lt;strong&gt;homepage&lt;/strong&gt; field for GitHub Pages — without it, your assets (CSS, images) often break after deployment.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;There's no excuse to keep a finished project sitting only on your local machine anymore. Pick Vercel or Netlify, connect your GitHub repo, and you'll have a shareable, live link in minutes — something you can put directly in a portfolio, a Fiverr gig, or a job application.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Muhammad Farhan&lt;/strong&gt; is a Frontend Developer specializing in React.js and Tailwind CSS, based in Dera Ismail Khan, Pakistan.&lt;br&gt;
&lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://muhammadfarhandev.netlify.app&quot;&gt;Muhammad Farhan&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23002/how-to-deploy-your-website-for-free-vercel-netlify-github-pages</guid>
<pubDate>Fri, 14 Aug 2026 05:00:00 +0000</pubDate>
</item>
<item>
<title>Excited to Share My Latest Full-Stack Project: NeighborHelp! 🤝</title>
<link>https://coderlegion.com/23722/excited-to-share-my-latest-full-stack-project-neighborhelp</link>
<description>&lt;p&gt;Have you ever been in a situation where you needed immediate help from someone nearby?&lt;/p&gt;
&lt;p&gt;Maybe you needed a blood donor, a local electrician, emergency transportation, pet care, or just someone in your neighborhood who could help quickly.&lt;/p&gt;
&lt;p&gt;Finding the right person at the right time isn't always easy.&lt;/p&gt;
&lt;p&gt;That's exactly why I built &lt;strong&gt;NeighborHelp&lt;/strong&gt; — a modern community platform that helps people connect with nearby neighbors and provide or receive help in real time.&lt;/p&gt;
&lt;p&gt;🌐 &lt;strong&gt;Live Demo:&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://neighborhelp99.vercel.app&quot;&gt;https://neighborhelp99.vercel.app&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-what-makes-neighborhelp-special-&quot;&gt;💡 What Makes NeighborHelp Special?&lt;/h3&gt;
&lt;h4 id=&quot;-smart-location-based-help&quot;&gt;📍 Smart Location-Based Help&lt;/h4&gt;
&lt;p&gt;NeighborHelp uses real-time location to show nearby help requests with distance filters like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Within 5 km&lt;/li&gt;
&lt;li&gt;Within 10 km&lt;/li&gt;
&lt;li&gt;Within 25 km&lt;/li&gt;
&lt;li&gt;Anywhere&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This makes finding nearby help simple and fast.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;-real-time-chat&quot;&gt;💬 Real-Time Chat&lt;/h4&gt;
&lt;p&gt;Users can instantly communicate using a built-in chat system powered by Socket.io.&lt;/p&gt;
&lt;p&gt;Features include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Online status&lt;/li&gt;
&lt;li&gt;Live typing indicators&lt;/li&gt;
&lt;li&gt;Instant messaging&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Everything updates in real time without refreshing the page.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;-instant-notifications&quot;&gt;🔔 Instant Notifications&lt;/h4&gt;
&lt;p&gt;Urgent requests shouldn't wait.&lt;/p&gt;
&lt;p&gt;NeighborHelp instantly sends:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Web Push Notifications&lt;/li&gt;
&lt;li&gt;Automated Email Alerts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;so people can respond as quickly as possible.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;-community-reputation-system&quot;&gt;🏆 Community Reputation System&lt;/h4&gt;
&lt;p&gt;Helping others deserves recognition.&lt;/p&gt;
&lt;p&gt;The platform includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;10-level badge system&lt;/li&gt;
&lt;li&gt;Reputation points&lt;/li&gt;
&lt;li&gt;Community success stories&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;to encourage active participation and build trust.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;-neighborbot-ai-assistant&quot;&gt;🤖 NeighborBot AI Assistant&lt;/h4&gt;
&lt;p&gt;An integrated AI assistant helps users by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Answering common questions&lt;/li&gt;
&lt;li&gt;Guiding new users&lt;/li&gt;
&lt;li&gt;Suggesting helpful actions&lt;/li&gt;
&lt;li&gt;Making the platform easier to use&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;-secure-authentication&quot;&gt;🛡️ Secure Authentication&lt;/h4&gt;
&lt;p&gt;Security was one of my top priorities while building this project.&lt;/p&gt;
&lt;p&gt;Features include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JWT Authentication&lt;/li&gt;
&lt;li&gt;Express Rate Limiting&lt;/li&gt;
&lt;li&gt;OTP-based Password Recovery&lt;/li&gt;
&lt;li&gt;Protected APIs&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;-tech-stack&quot;&gt;🛠️ Tech Stack&lt;/h2&gt;
&lt;h4 id=&quot;frontend&quot;&gt;Frontend&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Next.js 16&lt;/li&gt;
&lt;li&gt;React&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;li&gt;Vanilla CSS&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;backend&quot;&gt;Backend&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;Express.js&lt;/li&gt;
&lt;li&gt;Socket.io&lt;/li&gt;
&lt;li&gt;Web Push API&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;database-amp-deployment&quot;&gt;Database &amp;amp; Deployment&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Supabase PostgreSQL&lt;/li&gt;
&lt;li&gt;Vercel&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-what-i-learned&quot;&gt;💻 What I Learned&lt;/h3&gt;
&lt;p&gt;Building NeighborHelp from scratch helped me gain hands-on experience with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Full-Stack Development&lt;/li&gt;
&lt;li&gt;Real-Time Communication&lt;/li&gt;
&lt;li&gt;AI Integration&lt;/li&gt;
&lt;li&gt;Authentication &amp;amp; Security&lt;/li&gt;
&lt;li&gt;Geolocation Services&lt;/li&gt;
&lt;li&gt;Push Notifications&lt;/li&gt;
&lt;li&gt;Database Design&lt;/li&gt;
&lt;li&gt;Modern UI/UX&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It was an exciting journey that pushed me to think beyond just writing code and focus on solving a real-world community problem.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-i-d-love-your-feedback&quot;&gt;❤️ I'd Love Your Feedback&lt;/h3&gt;
&lt;p&gt;If you have a few minutes, please check out the project and let me know what you think.&lt;/p&gt;
&lt;p&gt;🌐 &lt;strong&gt;Live Demo:&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://neighborhelp99.vercel.app&quot;&gt;https://neighborhelp99.vercel.app&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Your feedback and suggestions will help me improve it even further.&lt;/p&gt;
&lt;p&gt;Thank you for reading! 🚀&lt;/p&gt;
&lt;h2 id=&quot;fullstackdevelopment-nextjs-react-nodejs-expressjs-socketio-supabase-softwareengineering-webdevelopment-buildinpublic-opensource-techcommunity-softwaredeveloper&quot;&gt;FullStackDevelopment #Nextjs #React #NodeJS #ExpressJS #SocketIO #Supabase #SoftwareEngineering #WebDevelopment #BuildInPublic #OpenSource #TechCommunity #SoftwareDeveloper&lt;/h2&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23722/excited-to-share-my-latest-full-stack-project-neighborhelp</guid>
<pubDate>Wed, 29 Jul 2026 06:12:56 +0000</pubDate>
</item>
<item>
<title>Best Hosting Platforms for Next.js in 2026: Who Actually Handles ISR &amp; PPR Correctly?</title>
<link>https://coderlegion.com/22746/best-hosting-platforms-for-next-js-in-2026-who-actually-handles-isr-ppr-correctly</link>
<description>&lt;p&gt;Every &quot;best hosting for Next.js&quot; post you'll find says roughly the same thing: Vercel is great, Netlify is a solid alternative, Cloudflare is fast, AWS is for enterprises. None of them tell you what actually happens when you deploy a page using &lt;strong&gt;Incremental Static Regeneration (ISR)&lt;/strong&gt; or &lt;strong&gt;Partial Prerendering (PPR)&lt;/strong&gt; to platforms that aren't Vercel.&lt;/p&gt;
&lt;p&gt;That's the gap this post fills. Instead of comparing dashboards and pricing pages, we're going to look at what each platform's adapter &lt;em&gt;actually does&lt;/em&gt; with ISR and PPR — because &quot;supported&quot; doesn't mean the same thing everywhere. This article focuses on architecture and feature behavior rather than benchmark results, since latency varies significantly by region, workload, cache hit ratio, and deployment configuration.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-distinction-nobody-explains-functional-vs-performance-fidelity&quot;&gt;The Distinction Nobody Explains: Functional vs. Performance Fidelity&lt;/h3&gt;
&lt;p&gt;This is the single most useful framing in this whole post, and it comes straight from Next.js's own platform documentation.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt; &lt;strong&gt;Tip:&lt;/strong&gt; Next.js draws a line between two levels of platform support:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Functional fidelity&lt;/strong&gt; — the feature works correctly. Your ISR page revalidates, your PPR shell renders.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance fidelity&lt;/strong&gt; — the feature works &lt;em&gt;optimally&lt;/em&gt;. The static shell is served from the CDN edge in milliseconds, not from a server function in another region.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;A platform can have full functional fidelity for PPR (it renders correctly) while having much lower performance fidelity than Vercel (it's served from a function instead of true edge-cached HTML). Both are &quot;PPR support&quot; — but they perform very differently in production. Keep this distinction in mind for every platform below.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-isr-and-ppr-are-hard-for-non-vercel-platforms&quot;&gt;Why ISR and PPR Are Hard for Non-Vercel Platforms&lt;/h3&gt;
&lt;p&gt;Quick recap if you need it: &lt;strong&gt;ISR&lt;/strong&gt; lets a static page revalidate itself in the background after a set time, without a full rebuild. &lt;strong&gt;PPR&lt;/strong&gt; (the rendering mode behind &lt;strong&gt;Cache Components&lt;/strong&gt;, Next.js's &lt;code&gt;&quot;use cache&quot;&lt;/code&gt; model) splits a single page into a static shell plus dynamic &quot;holes&quot; that stream in separately.&lt;/p&gt;
&lt;p&gt;Both features assume something most CDNs weren't built for: that cached HTML can be &lt;strong&gt;mutated after deployment&lt;/strong&gt; — purged, regenerated, and partially streamed — rather than treated as an immutable file tied to one deploy. Traditional CDN deploy models (Netlify, Cloudflare Pages, AWS Amplify, and others all once worked this way) assume deployed assets never change until the &lt;em&gt;next&lt;/em&gt; deploy. ISR and PPR break that assumption on purpose.&lt;/p&gt;
&lt;p&gt;This is exactly why Next.js, Netlify, Cloudflare, AWS Amplify, and Google Cloud spent over a year building a shared &lt;strong&gt;Deployment Adapter API&lt;/strong&gt;, which went stable in &lt;strong&gt;Next.js 16.2 (March 2026)&lt;/strong&gt;. Before this, most non-Vercel platforms were reverse-engineering Vercel's undocumented internal build output to support ISR at all. Now there's a public, versioned contract every platform builds against — including Vercel itself.&lt;/p&gt;
&lt;p&gt;That context matters because it means platform support for these features is improving rapidly and consistently right now, not stagnant.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;platform-by-platform-breakdown&quot;&gt;Platform-by-Platform Breakdown&lt;/h3&gt;
&lt;h4 id=&quot;vercel&quot;&gt;Vercel&lt;/h4&gt;
&lt;p&gt;Vercel built Next.js, so unsurprisingly it has both full functional &lt;strong&gt;and&lt;/strong&gt; the highest performance fidelity for ISR and PPR.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ISR:&lt;/strong&gt; Native. Stale content serves instantly while regeneration happens in the background, with sub-second revalidation propagation across their edge network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PPR / Cache Components:&lt;/strong&gt; This is where the gap is biggest. PPR's design intentionally splits a response into a CDN-cacheable static shell plus a dynamically-stitched stream appended at request time. As of this writing, &lt;strong&gt;Vercel is the only platform that stitches that static shell and the dynamic stream together at the CDN edge itself&lt;/strong&gt; — every other platform currently resolves PPR through a server/function layer instead of true edge stitching.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// app/products/[id]/page.tsx — works identically everywhere,
// but only Vercel currently serves the static part from true edge cache
async function getProduct(id: string) {
  &quot;use cache&quot;;
  const res = await fetch(`https://api.example.com/products/${id}`);
  return res.json();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; teams who want zero deployment-config overhead and the fastest possible PPR/ISR performance out of the box, and don't mind paying for that convenience.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ &lt;strong&gt;Common Mistake:&lt;/strong&gt; Assuming Vercel's free Hobby tier scales like its paid tier. Function execution time, image optimization, and bandwidth all meter separately — a project that feels free in development can post a real bill in production.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id=&quot;netlify&quot;&gt;Netlify&lt;/h4&gt;
&lt;p&gt;Netlify's Next.js Runtime is an officially maintained adapter, tested against every new stable Next.js release.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ISR:&lt;/strong&gt; Fully supported, including both time-based and on-demand revalidation, via Netlify's fine-grained caching primitives for the Full Route Cache and Data Cache.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PPR:&lt;/strong&gt; Supported — Netlify provisions a serverless Function specifically to handle SSR, ISR, &lt;strong&gt;and PPR&lt;/strong&gt;. This gives full functional fidelity, but the static shell isn't served straight from CDN edge cache the way Vercel's is — it still runs through that Function layer, which is the performance-fidelity gap described above.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// next.config.ts — no Netlify-specific config needed for PPR itself,
// the adapter detects and provisions the right Functions automatically
const nextConfig = {
  cacheComponents: true,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; teams who want Vercel-like functional completeness with a different pricing model or existing Netlify infrastructure (Forms, Identity, etc.).&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ &lt;strong&gt;Common Mistake:&lt;/strong&gt; Pointing Next.js rewrites at static files inside &lt;code&gt;public/&lt;/code&gt; — Netlify's adapter doesn't support that pattern, so routes that worked locally can silently 404 in production.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id=&quot;cloudflare-workers-via-opennext-&quot;&gt;Cloudflare Workers (via OpenNext)&lt;/h4&gt;
&lt;p&gt;Cloudflare doesn't have a native Next.js runtime — you deploy through the community-maintained &lt;code&gt;@opennextjs/cloudflare&lt;/code&gt; adapter, which transforms Next.js's build output into something Workers can run.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ISR:&lt;/strong&gt; Supported through the adapter's caching layer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PPR:&lt;/strong&gt; Documented as supported for the App Router, but it's newer and still maturing — Cloudflare's own docs list PPR alongside features like Node Middleware as areas with ongoing compatibility work. A dedicated, verified Cloudflare adapter built on Next.js's new stable Adapter API is in active development, which should close most remaining gaps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The catch:&lt;/strong&gt; image optimization needs to be delegated to Cloudflare Images or configured separately — &lt;code&gt;next/image&lt;/code&gt; doesn't work out of the box the way it does on Vercel.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Cloudflare-specific deploy flow
npm install @opennextjs/cloudflare
npx @opennextjs/cloudflare
npx wrangler deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; teams already invested in Cloudflare's edge network (Workers, D1, KV, R2) who want Next.js to live in the same ecosystem, and who can tolerate being slightly behind the bleeding edge on newer caching features.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ &lt;strong&gt;Common Mistake:&lt;/strong&gt; Forgetting the &lt;code&gt;nodejs_compat&lt;/code&gt; compatibility flag in &lt;code&gt;wrangler.toml&lt;/code&gt; / &lt;code&gt;wrangler.jsonc&lt;/code&gt;. Without it, plenty of Next.js server dependencies simply fail at runtime with confusing errors.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id=&quot;aws-amplify&quot;&gt;AWS Amplify&lt;/h4&gt;
&lt;p&gt;Amplify has supported Next.js SSR for a while, but it's noticeably behind on the newer caching model.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ISR:&lt;/strong&gt; Time-based revalidation works. &lt;strong&gt;On-demand ISR (&lt;code&gt;revalidatePath&lt;/code&gt; / &lt;code&gt;revalidateTag&lt;/code&gt; triggered manually) is explicitly not supported&lt;/strong&gt; — if your app relies on on-demand revalidation, it silently won't behave as expected on Amplify.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PPR / Cache Components:&lt;/strong&gt; Not clearly documented as supported at the time of writing. Amplify's adapter has had open compatibility issues tracking Next.js 16 support, which suggests PPR support is still catching up rather than production-proven.&lt;/li&gt;
&lt;li&gt;Build output is also capped at 220 MB for SSR apps — easy to hit with image-heavy or dependency-heavy projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; teams already deep in AWS infrastructure (IAM, CloudFront, existing AWS billing) who need simple SSR + scheduled ISR, and who can verify PPR behavior thoroughly before relying on it in production.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ &lt;strong&gt;Common Mistake:&lt;/strong&gt; Deploying with &lt;code&gt;output: &quot;export&quot;&lt;/code&gt; and expecting ISR or SSR to work. Static export disables the Next.js server runtime entirely — no SSR, no ISR, no API routes, full stop.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id=&quot;railway-amp-render-container-docker-platforms-&quot;&gt;Railway &amp;amp; Render (Container/Docker Platforms)&lt;/h4&gt;
&lt;p&gt;These two get grouped together because they take the same fundamental approach: you give them a Dockerfile or a Node process, and they run it. Functionally, this means &lt;strong&gt;ISR and PPR work exactly as well as they do in self-hosting&lt;/strong&gt; — because that's effectively what's happening.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Railway:&lt;/strong&gt; Has an official Next.js + Postgres deployment guide using &lt;code&gt;output: &quot;standalone&quot;&lt;/code&gt; in a Dockerfile. SSR, SSG, and ISR all work as expected since it's a real persistent Node process. PPR isn't explicitly documented but should work for the same reason — it's just &lt;code&gt;next start&lt;/code&gt;. The bigger concern reported in 2026 production usage isn't feature support, some users have reported reliability concerns around persistent storage and deployments, so production testing is important.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Render:&lt;/strong&gt; Supports SSR, ISR, and API routes through its Web Service deployment type, also via Docker or Git-based builds. Same story as Railway — because it's a real Node process, feature support isn't the limiting factor. Zero-downtime rolling deploys need deliberate configuration; they're not automatic the way they are on Vercel.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; teams who want container-based pricing predictability without writing their own Dockerfile-to-production pipeline from scratch, and who are comfortable being early on platform maturity.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ &lt;strong&gt;Common Mistake:&lt;/strong&gt; Treating Railway or Render as &quot;set and forget&quot; the way Vercel is. Both still require you to think about zero-downtime deploys, shared cache for multiple instances, and monitoring — that operational layer doesn't disappear just because there's no explicit Next.js adapter to configure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id=&quot;self-hosting-docker-vps-fly-io-cloud-run-&quot;&gt;Self-Hosting (Docker, VPS, Fly.io, Cloud Run)&lt;/h4&gt;
&lt;p&gt;This is the one with the cleanest answer of all of them, straight from Next.js's own documentation:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;A single &lt;code&gt;next start&lt;/code&gt; process handles every Next.js feature correctly: Server Components, ISR, PPR, Cache Components, Server Actions, Proxy, and &lt;code&gt;after()&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Full functional fidelity, no adapter, no caveats — because there's no translation layer between your app and the framework. The tradeoffs aren't about features; they're about who's doing the operational work.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-dockerfile&quot;&gt;# Minimal self-hosting Dockerfile
FROM node:22-alpine AS base
WORKDIR /app
COPY . .
RUN npm ci &amp;amp;&amp;amp; npm run build

FROM node:22-alpine AS runner
WORKDIR /app
COPY --from=base /app/.next/standalone ./
COPY --from=base /app/.next/static ./.next/static
EXPOSE 3000
CMD [&quot;node&quot;, &quot;server.js&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What you give up is everything Vercel/Netlify automate for you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Multi-instance cache coordination&lt;/strong&gt; — if you scale beyond one server, &lt;code&gt;revalidateTag()&lt;/code&gt; only invalidates the instance that handled the request by default. You need a shared cache handler (commonly Redis) so other instances learn about invalidations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Streaming infrastructure&lt;/strong&gt; — PPR's time-to-first-byte advantage depends on your reverse proxy actually supporting streaming responses. Without it, the static shell and dynamic content get buffered and sent together, which still works but quietly loses PPR's main benefit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;All the DevOps&lt;/strong&gt;, full stop: TLS, zero-downtime deploys, observability, scaling rules.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; teams with existing DevOps capacity, strict data residency or compliance requirements, or sustained traffic where Vercel's usage-based pricing starts to outpace flat compute costs.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ &lt;strong&gt;Common Mistake:&lt;/strong&gt; Self-hosting without &lt;code&gt;output: &quot;standalone&quot;&lt;/code&gt; in &lt;code&gt;next.config.ts&lt;/code&gt;. Without it, your Docker image drags in the entire &lt;code&gt;node_modules&lt;/code&gt; tree instead of a trimmed production bundle.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;quick-comparison&quot;&gt;Quick Comparison&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Platform &lt;/th&gt;&lt;th&gt;ISR (time-based) &lt;/th&gt;&lt;th&gt;ISR (on-demand) &lt;/th&gt;&lt;th&gt;PPR / Cache Components &lt;/th&gt;&lt;th&gt;Performance Fidelity&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Vercel&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;✅ Native &lt;/td&gt;&lt;td&gt;✅ Native &lt;/td&gt;&lt;td&gt;✅ True edge-stitched shell &lt;/td&gt;&lt;td&gt;Highest&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Netlify&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;✅ Via adapter &lt;/td&gt;&lt;td&gt;✅ Via adapter &lt;/td&gt;&lt;td&gt;✅ Via Function layer &lt;/td&gt;&lt;td&gt;High&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Cloudflare Workers&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;✅ Via OpenNext &lt;/td&gt;&lt;td&gt; Maturing &lt;/td&gt;&lt;td&gt; Documented, still maturing &lt;/td&gt;&lt;td&gt;Medium&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;AWS Amplify&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;✅ Time-based only &lt;/td&gt;&lt;td&gt;❌ Not supported &lt;/td&gt;&lt;td&gt; Unclear / catching up &lt;/td&gt;&lt;td&gt;Medium-Low&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Railway / Render&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;✅ (it's just Node) &lt;/td&gt;&lt;td&gt;✅ (it's just Node) &lt;/td&gt;&lt;td&gt;✅ (it's just Node) &lt;/td&gt;&lt;td&gt;Depends on your setup&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Self-hosted&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;✅ Full fidelity &lt;/td&gt;&lt;td&gt;✅ Full fidelity &lt;/td&gt;&lt;td&gt;✅ Full fidelity &lt;/td&gt;&lt;td&gt;You configure it&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;so-which-one-should-you-actually-use-&quot;&gt;So, Which One Should You Actually Use?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Default choice for most SaaS/MVP work:&lt;/strong&gt; Vercel. The performance-fidelity gap on PPR is real, and for most projects, not having to think about adapters or streaming infrastructure is worth the premium.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Want Vercel-level functional support on a different platform or pricing model:&lt;/strong&gt; Netlify is the most production-proven non-Vercel option for ISR and PPR today.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Already living in Cloudflare's ecosystem:&lt;/strong&gt; Workers via OpenNext is viable, just confirm PPR behavior for your specific routes before launch — it's improving fast but newer than Netlify's support.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;On AWS for compliance or org reasons:&lt;/strong&gt; Amplify works for SSR + scheduled ISR; don't build a feature around on-demand revalidation or PPR there yet without testing thoroughly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Want container simplicity without managing your own VPS:&lt;/strong&gt; Railway or Render — but budget time for reliability testing, especially anything stateful.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Have DevOps capacity, compliance needs, or are past the point where usage-based pricing makes sense:&lt;/strong&gt; self-host. Every feature works correctly by default; you're trading platform fees for engineering time.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;frequently-asked-questions&quot;&gt;Frequently Asked Questions&lt;/h3&gt;
&lt;h4 id=&quot;does-supports-isr-mean-it-works-exactly-like-vercel-&quot;&gt;Does &quot;supports ISR&quot; mean it works exactly like Vercel?&lt;/h4&gt;
&lt;p&gt;Not necessarily. Use the functional vs. performance fidelity distinction from earlier in this post — most platforms now have functional support, but the experience (latency, edge caching, revalidation propagation speed) still varies.&lt;/p&gt;
&lt;h4 id=&quot;is-ppr-available-everywhere-yet-&quot;&gt;Is PPR available everywhere yet?&lt;/h4&gt;
&lt;p&gt;Functionally, on most major platforms — yes. With the same performance characteristics as Vercel — no, not yet. Vercel currently has unique edge-stitching infrastructure that other platforms haven't replicated.&lt;/p&gt;
&lt;h4 id=&quot;will-the-new-adapter-api-make-all-platforms-equal-eventually-&quot;&gt;Will the new Adapter API make all platforms equal eventually?&lt;/h4&gt;
&lt;p&gt;It makes them &lt;em&gt;correct&lt;/em&gt; against the same shared contract, which is a big deal for portability. It doesn't automatically make them equally &lt;em&gt;fast&lt;/em&gt; — that still depends on each platform's own CDN and edge infrastructure investment.&lt;/p&gt;
&lt;h4 id=&quot;is-self-hosting-actually-cheaper-&quot;&gt;Is self-hosting actually cheaper?&lt;/h4&gt;
&lt;p&gt;Compute usually is. Total cost isn't always — factor in the engineering hours for setup and ongoing maintenance, not just server bills, before assuming self-hosting wins on price.&lt;/p&gt;
&lt;h4 id=&quot;can-i-switch-platforms-later-if-i-start-with-vercel-&quot;&gt;Can I switch platforms later if I start with Vercel?&lt;/h4&gt;
&lt;p&gt;Yes, especially now that the Adapter API is stable and shared across platforms. It's not zero-effort, but it's far less risky than it was before this API existed.&lt;/p&gt;
&lt;h5 id=&quot;platform-migration-difficulty&quot;&gt;Platform Migration Difficulty&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Move From            &lt;/th&gt;&lt;th&gt;Difficulty&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Vercel → Netlify     &lt;/td&gt;&lt;td&gt;Low&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Vercel → OpenNext    &lt;/td&gt;&lt;td&gt;Medium&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Vercel → Self-hosted &lt;/td&gt;&lt;td&gt;Medium&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Amplify → Vercel     &lt;/td&gt;&lt;td&gt;Low&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h3&gt;
&lt;p&gt;&quot;Best Next.js hosting&quot; isn't really a single ranking — it's a tradeoff between performance fidelity, pricing model, and how much operational work you want to own. Vercel still leads on PPR/ISR performance specifically because it built the rendering model the rest of the ecosystem is now catching up to. Everyone else is closing that gap at different speeds, and the new shared Adapter API is exactly why that gap is closing faster in 2026 than it ever has before.&lt;/p&gt;
&lt;p&gt;If you're deploying something today: pick based on where your team already lives, then verify ISR/PPR behavior yourself in a staging deploy rather than trusting a docs page's checkmark — the distinction between &quot;works&quot; and &quot;works well&quot; is exactly what most comparison posts skip.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://nextjs.org/blog/nextjs-across-platforms&quot;&gt;Next.js: Across Platforms — Adapters, OpenNext, and Commitments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://nextjs.org/docs/app/guides/deploying-to-platforms&quot;&gt;Next.js Deploying to Platforms Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://nextjs.org/docs/app/guides/ppr-platform-guide&quot;&gt;Next.js PPR Platform Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://nextjs.org/docs/app/guides/self-hosting&quot;&gt;Next.js Self-Hosting Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.netlify.com/build/frameworks/framework-setup-guides/nextjs/overview/&quot;&gt;Netlify Next.js Runtime Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developers.cloudflare.com/workers/framework-guides/web-apps/nextjs/&quot;&gt;Cloudflare Next.js (OpenNext) Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;continue-learning&quot;&gt;Continue Learning&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://devstacked.tech/blog/nextjs-rendering-strategies-explained&quot;&gt;Next.js Rendering Strategies Explained: SSR, SSG, CSR, ISR &amp;amp; Cache Components (2026)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://devstacked.tech/blog/saas-starter-architecture-nextjs&quot;&gt;SaaS Starter Architecture with Next.js 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22746/best-hosting-platforms-for-next-js-in-2026-who-actually-handles-isr-ppr-correctly</guid>
<pubDate>Wed, 15 Jul 2026 10:05:54 +0000</pubDate>
</item>
<item>
<title>The Developer's Worst Nightmare: Vercel Has My Code, My Hard Drive Doesn't</title>
<link>https://coderlegion.com/21328/the-developers-worst-nightmare-vercel-has-my-code-my-hard-drive-doesnt</link>
<description>&lt;p&gt;We’ve all been there. A sudden laptop crash, an accidental rm -rf in the wrong directory, or a Git repository that somehow vanished into the ether. You look at your screen in horror, realizing your local source code is completely gone. But then you look at your browser tab—your website is still running perfectly fine on Vercel.&lt;/p&gt;
&lt;p&gt;While Vercel is a hosting platform and not a cloud backup service, it is entirely possible to piece your project back together using what Vercel has cached. Here is the exact, strategic battle plan to recover your hard work based on how Vercel processes your deployments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Complications:&lt;/strong&gt; What You Are Up Against&lt;br&gt;
Before you start clicking around, you need to understand the limitations. Vercel does not store a neat, downloadable .zip file of your original local directory. When you deploy, Vercel takes your code, builds it, and distributes the compiled output.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The source code is heavily obfuscated and bundled:&lt;/strong&gt; If you built a React, Next.js, or Vue app, Vercel compiles your readable components into giant, minimized JavaScript files.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The original server-side logic is hidden:&lt;/strong&gt; Any API routes or server-side functions (like getServerSideProps or Node.js endpoints) are compiled into isolated AWS Lambda functions or Edge functions that you cannot easily read or download.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Asset fragmentation:&lt;/strong&gt; While public assets like images and CSS are accessible, they are scattered across Vercel’s Content Delivery Network (CDN).&lt;/p&gt;
&lt;p&gt;Missing environment variables: Your .env.local file was never uploaded to your Git provider, meaning secrets and API keys must be extracted manually from the Vercel dashboard.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Recovery Strategy: Step-by-Step&lt;/strong&gt;&lt;br&gt;
Because we cannot just hit a &quot;download source&quot; button, we have to approach this problem dynamically based on what type of project you deployed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trigger Point 1: Leverage the Git History (Your Best Chance)&lt;/strong&gt;&lt;br&gt;
Even if your local machine wiped the repository, check the Vercel Dashboard under your project settings. Look at the connected Git repository link. If you deployed via GitHub, GitLab, or Bitbucket, the code still exists on their servers. All you need to do is run git clone [repository-url] on your new machine to get 100% of your source code back.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trigger Point 2: Scrape the Source Maps via Developer Tools&lt;/strong&gt;&lt;br&gt;
If you deployed a frontend framework and accidentally deleted the remote Git repo too, you can use Source Maps. If you didn't disable them in your production build, open your live website, hit F12 to open Developer Tools, and navigate to the Sources or Debugger tab. If source maps are active, the browser reconstructs your exact original files (like App.jsx or index.tsx) right in front of you. You can literally copy and paste your original components back into a new folder.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trigger Point 3: Pull Compiled Output via Vercel CLI&lt;/strong&gt;&lt;br&gt;
If the top two methods fail, you can use the Vercel Command Line Interface (CLI) to see what Vercel is holding onto. Open your terminal, log into your account using vercel login, and use the vercel project clone command or inspect the .vercel/output folder by running a local build check. While this mostly pulls down the built, static HTML/JS assets rather than your raw source code, it gives you the functional building blocks to reverse-engineer your layout.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trigger Point 4: Salvage Your Environment Variables&lt;/strong&gt;&lt;br&gt;
A functional app needs its keys. Go to your Vercel Dashboard -&amp;gt; Project Settings -&amp;gt; Environment Variables. Vercel decrypts these for you on the dashboard. Copy these values immediately and save them into a new local .env file so your API connections don't break when you start rebuild attempts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Moving Forward: Lock It Down&lt;/strong&gt;&lt;br&gt;
Once you have pieced your files back together, ensure this never happens again. Always back up your code upstream. Initialize a fresh Git repository immediately, push it to a secure cloud provider, and consider using a secondary cloud backup for your local machine's Documents or Developer folders.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sumita&lt;br&gt;
Web Developer&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/21328/the-developers-worst-nightmare-vercel-has-my-code-my-hard-drive-doesnt</guid>
<pubDate>Wed, 24 Jun 2026 17:08:53 +0000</pubDate>
</item>
<item>
<title>Back-End Web Development — VPS vs Vercel vs Netlify</title>
<link>https://coderlegion.com/20868/back-end-web-development-vps-vs-vercel-vs-netlify</link>
<description>&lt;h2 id=&quot;introduction-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Every great web application with millions of users has an even greater back end — and it has to be. Accessing your app over a prolonged period of time will test the integrity, availability, and speed of your back end. Backend technology can be inexpensive, or it can cost you thousands of dollars. So what's the deal here?   &lt;/p&gt;
&lt;p&gt;Let me warn you that this post is highly opinionated. I am sharing the tools that I use and how I use them.&lt;/p&gt;
&lt;p&gt;For my back end that powers my web apps, I use Directus for my headless CMS, supported by a PostgreSQL and Redis database, hosted on a VPS, and managed by Coolify. Wow, that is a mouthful — and on my channel I explore how they all work together.&lt;/p&gt;
&lt;p&gt;So let's tackle each technology one at a time, starting with the VPS.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-vps-&quot;&gt;What is a VPS?&lt;/h2&gt;
&lt;p&gt;A Virtual Private Server, known as a VPS, is a virtual environment created on a physical server. Think of it like an apartment building — everyone shares the same physical structure, but each unit has its own private space, utilities, and security. While multiple VPS instances share a physical server, be careful not to confuse this with shared hosting.&lt;/p&gt;
&lt;p&gt; Each VPS is allocated its own dedicated resources, which are restricted to that VPS for as long as it is active. Therefore, the performance of a VPS is not directly affected by the usage of other VPS instances, but rather by the underlying performance of the physical server itself.&lt;/p&gt;
&lt;h2 id=&quot;what-are-the-benefits-of-a-vps-&quot;&gt;What are the benefits of a VPS?&lt;/h2&gt;
&lt;p&gt;There are several benefits to consider when deciding on virtual private server hosting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Greater control&lt;/strong&gt; — Compared to shared hosting, you have root access and can fully customize your server environment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dedicated resources&lt;/strong&gt; — Allocated CPU, memory, and storage help ensure consistent performance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt; — You can easily scale resources up or down to accommodate changing traffic and application demands.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost-effectiveness&lt;/strong&gt; — A VPS typically offers a balance between the affordability of shared hosting and the power of a dedicated server.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improved security&lt;/strong&gt; — Isolation from other users on the same physical server enhances security.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Choice of operating system&lt;/strong&gt; — You can choose the operating system that best suits your needs, such as Linux or Windows.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-does-it-stack-up-against-vercel-or-netlify-&quot;&gt;How does it stack up against Vercel or Netlify?&lt;/h2&gt;
&lt;p&gt;Vercel offers minimal setup with Git integration and fast deployment right out of the box. It has a free Hobby plan, but it is strictly for personal, non-commercial use. Once your app grows and needs to scale, you will need to move to a paid plan. &lt;/p&gt;
&lt;p&gt;The Pro plan starts at $20 per user per month, and also covers serverless functions. Despite the name, serverless code still runs on a physical server — however, the infrastructure management, such as scaling, security patching, and provisioning, is handled entirely by the cloud provider. The main factor to watch carefully is cost. &lt;/p&gt;
&lt;p&gt;Vercel uses usage-based billing, and costs can escalate quickly — especially since Turbo build machines became the default for new Pro projects in February 2026, at 0.126USD  per build minute. A moderate team workflow can generate over $400 per month in build costs alone, before bandwidth and compute charges. I have seen some alarming Vercel bills shared online by customers, which means you need to fully understand the pricing model before you commit.&lt;/p&gt;
&lt;p&gt;Netlify has historically been more suited to static sites and composable web applications. Composable applications are software systems built from independent, interchangeable modules rather than a single rigid code base. Netlify also has Git integration, customizable build plugins, and serverless functions. Netlify moved to a credit-based pricing model in September 2025, which is &lt;br&gt;
designed to simplify metered billing. &lt;/p&gt;
&lt;p&gt;As of April 2026, the Pro plan costs 20USD per month and now includes unlimited team member seats, which is an improvement over the previous per-seat model. However, teams working on active projects with real traffic can burn through their credit allocation quickly, and credit pack add-ons at 10USD per 1,500 credits mean teams can regularly spend 40USD to 80USD or more per month beyond the base subscription. Your overall control is also more limited compared to a VPS, and you will still face a monthly cost as your app grows.&lt;/p&gt;
&lt;h2 id=&quot;now-the-vps-&quot;&gt;Now the VPS.&lt;/h2&gt;
&lt;p&gt;VPS prices can grow as your app grows, but in my experience at a slower and more predictable rate — with no surprise charges. However, if you manage a VPS yourself, it requires understanding web servers, firewalls, operating systems, caching, and more. It can get complex very quickly and may cause you to spend more time managing the server than building and scaling your app.&lt;/p&gt;
&lt;p&gt;That is why some developers and business owners hire a team to handle it. Small teams may not have the budget for a dedicated infrastructure team, so they often opt for a more convenient managed solution.&lt;/p&gt;
&lt;p&gt;There is one tool, however, that I think is worth mentioning and is a genuine game changer — and that is Coolify. In a later post I will go into more detail about what Coolify is and what it does. Coolify is a self-hostable platform that makes managing your VPS significantly easier. It offers Git integration, runs apps in Dockerized containers, handles HTTPS automatically, and includes a built-in web server that works out of the box with no manual configuration required. This makes the VPS a very real and competitive option worth considering.&lt;/p&gt;
&lt;p&gt;If you choose a solid hosting provider and pair it with the right tools, you can make this an absolute dream to work with.&lt;/p&gt;
&lt;p&gt;Now don’t get me wrong, even with Coolify there are some configurations that you will have to make, but I do believe a VPS is a great solution for a start up, mid-size or enterprise scaled app, with the right tools.&lt;/p&gt;
&lt;h2 id=&quot;references-1&quot;&gt;References&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;• https://cloud.google.com/learn/what-is-a-virtual-private-server 
• https://aws.amazon.com/what-is/vps/ 
• https://www.ibm.com/think/topics/vps 
• https://www.scalahosting.com/blog/what-is-a-vps-technical-explanation/ 
• https://www.dreamhost.com/blog/beginners-guide-vps/ 
• https://vercel.com/pricing 
• https://www.netlify.com/pricing/ 
• https://bejamas.com/blog/self-hosting-vs-vercel-and-netlify-which-solution-is-right
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/20868/back-end-web-development-vps-vs-vercel-vs-netlify</guid>
<pubDate>Thu, 18 Jun 2026 03:34:03 +0000</pubDate>
</item>
<item>
<title>Growth Truth: Handling the Referral Spike</title>
<link>https://coderlegion.com/13898/growth-truth-handling-the-referral-spike</link>
<description>&lt;hr&gt;
&lt;h2 id=&quot;growth-truth-handling-the-referral-spike&quot;&gt;Growth Truth: Handling the Referral Spike&lt;/h2&gt;
&lt;p&gt;When traffic spikes, what breaks first — &lt;strong&gt;routing&lt;/strong&gt;, &lt;strong&gt;LLM quotas&lt;/strong&gt;, or &lt;strong&gt;database write paths&lt;/strong&gt;? Here is how we framed a real referral window against a &lt;strong&gt;stateless&lt;/strong&gt; chat surface.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;headline-traffic-ga4-&quot;&gt;Headline traffic (GA4)&lt;/h3&gt;
&lt;p&gt;Figures below are from &lt;strong&gt;Google Analytics 4&lt;/strong&gt; (Marketing performance) for a fixed &lt;strong&gt;28-day&lt;/strong&gt; window. GA4 can revise counts slightly as sessions reconcile; we cite the &lt;strong&gt;exported&lt;/strong&gt; values for this slice.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Field &lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Date range&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;&lt;strong&gt;2026-03-06&lt;/strong&gt; → &lt;strong&gt;2026-04-02&lt;/strong&gt; (28 days)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Active users&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;&lt;strong&gt;4,669&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;New users&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;&lt;strong&gt;4,500&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Two different dials:&lt;/strong&gt; GA4 answers “how many people touched the property in this window.” Product-side analytics (referral events, campaign attribution, Stripe-adjacent rollups) answer “how did growth mechanics behave?” They are &lt;strong&gt;complementary&lt;/strong&gt;, not interchangeable — and &lt;strong&gt;GA4 active users&lt;/strong&gt; are not the same thing as &lt;strong&gt;Firebase Auth&lt;/strong&gt; sign-in counts unless you say so explicitly.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;stateless-inference-and-where-burst-load-lands&quot;&gt;Stateless inference and where burst load lands&lt;/h3&gt;
&lt;p&gt;The app’s &lt;strong&gt;chat&lt;/strong&gt; path is &lt;strong&gt;stateless&lt;/strong&gt; for portfolio payloads (&lt;code&gt;/api/ai/chat&lt;/code&gt; — see Part 1). Under spike load, stress concentrates on:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Edge / routing&lt;/strong&gt; — session affinity is not the model; &lt;strong&gt;referral survival&lt;/strong&gt; is. We &lt;strong&gt;307&lt;/strong&gt; apex → &lt;code&gt;www&lt;/code&gt; so &lt;code&gt;?ref=&lt;/code&gt; and cookies stay coherent:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// middleware.ts — canonical host: apex → www
if (host === 'pocketportfolio.app') {
  url.hostname = 'www.pocketportfolio.app';
  return NextResponse.redirect(url, 307);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Serverless limits&lt;/strong&gt; — &lt;code&gt;maxDuration = 30&lt;/code&gt; on the chat route; streaming responses; provider rate limits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Firestore&lt;/strong&gt; — quota counters (&lt;code&gt;aiUsage&lt;/code&gt;), analytics metadata (&lt;code&gt;toolUsage&lt;/code&gt;), &lt;strong&gt;&lt;code&gt;referralEvents&lt;/code&gt;&lt;/strong&gt; — hot writes, not giant prompt logs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; stateless inference keeps the &lt;strong&gt;heaviest sensitive payload&lt;/strong&gt; off disk; growth still needs &lt;strong&gt;solid&lt;/strong&gt; indexes and &lt;strong&gt;realistic&lt;/strong&gt; capacity planning for referrals and quotas.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-tends-to-fail-first&quot;&gt;What tends to fail first&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Referral attribution&lt;/strong&gt; (middleware, cookies) — if this slips, growth looks “direct only.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LLM provider&lt;/strong&gt; throttling or streaming failures.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Firestore&lt;/strong&gt; write contention on high-frequency collections during campaigns.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Part 4 of &lt;strong&gt;Sovereign Engineering&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read the full &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.pocketportfolio.app/book/sovereign-intelligence&quot;&gt;Sovereign Intelligence&lt;/a&gt; book or &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.pocketportfolio.app&quot;&gt;try the app&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/13898/growth-truth-handling-the-referral-spike</guid>
<pubDate>Wed, 15 Apr 2026 12:04:00 +0000</pubDate>
</item>
<item>
<title>Getting Started with the Vercel AI SDK (Beginner to Working Chat App)</title>
<link>https://coderlegion.com/10167/getting-started-with-the-vercel-ai-sdk-beginner-to-working-chat-app</link>
<description>&lt;p&gt;If you’re building AI features like &lt;strong&gt;chatbots&lt;/strong&gt;, &lt;strong&gt;content generators&lt;/strong&gt;, &lt;strong&gt;AI agents&lt;/strong&gt;, or &lt;strong&gt;streaming assistants&lt;/strong&gt;, you’ll quickly realize that the “LLM call” is only 20% of the work.&lt;/p&gt;
&lt;p&gt;The other 80% is:&lt;br&gt;
✅ streaming responses&lt;br&gt;
✅ UI updates in real-time&lt;br&gt;
✅ tool calling&lt;br&gt;
✅ handling errors &amp;amp; retries&lt;br&gt;
✅ server/client integration&lt;br&gt;
✅ building a clean developer experience&lt;/p&gt;
&lt;p&gt;That’s where the &lt;strong&gt;Vercel AI SDK&lt;/strong&gt; shines.&lt;/p&gt;
&lt;p&gt;In this blog, you’ll learn how to get started with the Vercel AI SDK and build a simple &lt;strong&gt;streaming chat app&lt;/strong&gt; using &lt;strong&gt;Next.js&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-is-the-vercel-ai-sdk-&quot;&gt;What is the Vercel AI SDK?&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;Vercel AI SDK&lt;/strong&gt; is a set of libraries and utilities to build AI-powered apps with great UX:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Streaming responses (token-by-token)&lt;/li&gt;
&lt;li&gt;React hooks for chat and completion&lt;/li&gt;
&lt;li&gt;Easy server routes (Next.js App Router)&lt;/li&gt;
&lt;li&gt;Tool/function calling support&lt;/li&gt;
&lt;li&gt;Provider integrations (OpenAI, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s designed for &lt;strong&gt;modern full-stack apps&lt;/strong&gt;, especially in the Next.js ecosystem.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-you-ll-build&quot;&gt;What You’ll Build&lt;/h3&gt;
&lt;p&gt;By the end, you’ll have:&lt;/p&gt;
&lt;p&gt;✅ A Next.js app&lt;br&gt;
✅ A chat UI&lt;br&gt;
✅ An API route that streams AI responses&lt;br&gt;
✅ Working end-to-end in minutes&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;step-1-create-a-next-js-app&quot;&gt;Step 1: Create a Next.js App&lt;/h2&gt;
&lt;p&gt;Run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npx create-next-app@latest vercel-ai-sdk-demo
cd vercel-ai-sdk-demo
npm run dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Choose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TypeScript ✅&lt;/li&gt;
&lt;li&gt;App Router ✅&lt;/li&gt;
&lt;li&gt;Tailwind (optional but recommended) ✅&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;step-2-install-the-vercel-ai-sdk&quot;&gt;Step 2: Install the Vercel AI SDK&lt;/h2&gt;
&lt;p&gt;Install the SDK:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install ai
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then install an AI provider package (OpenAI is common):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install @ai-sdk/openai
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;step-3-add-your-api-key&quot;&gt;Step 3: Add Your API Key&lt;/h2&gt;
&lt;p&gt;Create &lt;code&gt;.env.local&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;OPENAI_API_KEY=your_api_key_here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Restart the dev server after adding env vars.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;step-4-create-the-streaming-chat-api-route&quot;&gt;Step 4: Create the Streaming Chat API Route&lt;/h2&gt;
&lt;p&gt;In Next.js App Router, create:&lt;/p&gt;
&lt;p&gt; &lt;code&gt;app/api/chat/route.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { openai } from &quot;@ai-sdk/openai&quot;;
import { streamText } from &quot;ai&quot;;

export async function POST(req: Request) {
  const { messages } = await req.json();

  const result = await streamText({
    model: openai(&quot;gpt-4o-mini&quot;),
    messages,
    system: &quot;You are a helpful assistant. Keep answers short and clear.&quot;,
  });

  return result.toDataStreamResponse();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;what-s-happening-here-&quot;&gt;What’s happening here?&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;messages&lt;/code&gt; contains the full chat history&lt;/li&gt;
&lt;li&gt;&lt;code&gt;streamText()&lt;/code&gt; streams the model output&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toDataStreamResponse()&lt;/code&gt; returns a streaming response to the UI&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;step-5-build-the-chat-ui-with-usechat-&quot;&gt;Step 5: Build the Chat UI with &lt;code&gt;useChat()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Now create a UI page:&lt;/p&gt;
&lt;p&gt; &lt;code&gt;app/page.tsx&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&quot;use client&quot;;

import { useChat } from &quot;ai/react&quot;;

export default function Home() {
  const { messages, input, handleInputChange, handleSubmit, isLoading } =
    useChat({ api: &quot;/api/chat&quot; });

  return (
    &amp;lt;main style={{ maxWidth: 700, margin: &quot;40px auto&quot;, padding: 16 }}&amp;gt;
      &amp;lt;h1 style={{ fontSize: 24, fontWeight: 700 }}&amp;gt;Vercel AI SDK Chat&amp;lt;/h1&amp;gt;

      &amp;lt;div style={{ marginTop: 20, border: &quot;1px solid #ddd&quot;, padding: 16 }}&amp;gt;
        {messages.map((m) =&amp;gt; (
          &amp;lt;div key={m.id} style={{ marginBottom: 12 }}&amp;gt;
            &amp;lt;strong&amp;gt;{m.role}:&amp;lt;/strong&amp;gt; {m.content}
          &amp;lt;/div&amp;gt;
        ))}
      &amp;lt;/div&amp;gt;

      &amp;lt;form onSubmit={handleSubmit} style={{ marginTop: 16, display: &quot;flex&quot; }}&amp;gt;
        &amp;lt;input
          value={input}
          onChange={handleInputChange}
          placeholder=&quot;Ask something...&quot;
          style={{ flex: 1, padding: 10, border: &quot;1px solid #ccc&quot; }}
        /&amp;gt;
        &amp;lt;button
          type=&quot;submit&quot;
          disabled={isLoading}
          style={{ marginLeft: 8, padding: &quot;10px 14px&quot; }}
        &amp;gt;
          Send
        &amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/main&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;step-6-run-it&quot;&gt;Step 6: Run It&lt;/h2&gt;
&lt;p&gt;Start your app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open:&lt;br&gt;
 &lt;code&gt;http://localhost:3000&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Now type a message and watch the AI respond in real-time.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;understanding-messages&quot;&gt;Understanding &lt;code&gt;messages&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;messages&lt;/code&gt; is an array like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;[
  { role: &quot;user&quot;, content: &quot;Hello&quot; },
  { role: &quot;assistant&quot;, content: &quot;Hi! How can I help?&quot; }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The SDK manages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;appending new messages&lt;/li&gt;
&lt;li&gt;streaming assistant messages&lt;/li&gt;
&lt;li&gt;updating UI automatically&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;add-a-better-ui-optional-&quot;&gt;Add a Better UI (Optional)&lt;/h2&gt;
&lt;p&gt;You can style messages by role:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;{messages.map((m) =&amp;gt; (
  &amp;lt;div
    key={m.id}
    style={{
      padding: 12,
      borderRadius: 12,
      marginBottom: 10,
      background: m.role === &quot;user&quot; ? &quot;#f2f2f2&quot; : &quot;#e7f5ff&quot;,
    }}
  &amp;gt;
    &amp;lt;strong&amp;gt;{m.role}:&amp;lt;/strong&amp;gt; {m.content}
  &amp;lt;/div&amp;gt;
))}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;bonus-add-tool-calling-basic-example-&quot;&gt;Bonus: Add Tool Calling (Basic Example)&lt;/h2&gt;
&lt;p&gt;Tool calling allows your AI to call functions like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;search database&lt;/li&gt;
&lt;li&gt;fetch weather&lt;/li&gt;
&lt;li&gt;calculate tax&lt;/li&gt;
&lt;li&gt;call APIs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example concept:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;tools: {
  getTime: {
    description: &quot;Get current server time&quot;,
    execute: async () =&amp;gt; new Date().toISOString(),
  },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is where Vercel AI SDK becomes powerful for &lt;strong&gt;agentic workflows&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;common-issues-amp-fixes&quot;&gt;Common Issues &amp;amp; Fixes&lt;/h2&gt;
&lt;h3 id=&quot;-openai-api-key-missing-&quot;&gt;❌ “OPENAI_API_KEY missing”&lt;/h3&gt;
&lt;p&gt;Fix:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensure &lt;code&gt;.env.local&lt;/code&gt; exists&lt;/li&gt;
&lt;li&gt;Restart dev server&lt;/li&gt;
&lt;li&gt;Check variable name&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;-no-streaming-happens&quot;&gt;❌ No streaming happens&lt;/h3&gt;
&lt;p&gt;Fix:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;useChat()&lt;/code&gt; properly&lt;/li&gt;
&lt;li&gt;Ensure API route returns &lt;code&gt;toDataStreamResponse()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;-build-fails-on-deployment&quot;&gt;❌ Build fails on deployment&lt;/h3&gt;
&lt;p&gt;Fix:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add env var in Vercel dashboard&lt;/li&gt;
&lt;li&gt;Ensure route uses server runtime properly&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;production-tips-best-practices-&quot;&gt;Production Tips (Best Practices)&lt;/h2&gt;
&lt;h4 id=&quot;-keep-prompts-stable&quot;&gt;✅ Keep prompts stable&lt;/h4&gt;
&lt;p&gt;Use a clear system prompt and avoid changing it too often.&lt;/p&gt;
&lt;h4 id=&quot;-limit-message-history&quot;&gt;✅ Limit message history&lt;/h4&gt;
&lt;p&gt;For performance, send only last N messages.&lt;/p&gt;
&lt;h4 id=&quot;-add-safety&quot;&gt;✅ Add safety&lt;/h4&gt;
&lt;p&gt;Filter harmful content or enforce policies.&lt;/p&gt;
&lt;h4 id=&quot;-add-logging&quot;&gt;✅ Add logging&lt;/h4&gt;
&lt;p&gt;Log prompts, latency, and tool usage.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-to-build-next&quot;&gt;What to Build Next&lt;/h2&gt;
&lt;p&gt;Once you have a basic chat working, you can extend it into:&lt;/p&gt;
&lt;p&gt; AI Customer Support Assistant&lt;br&gt;
 RAG-powered Knowledge Bot&lt;br&gt;
 AI Agent for Jira / GitHub tasks&lt;br&gt;
 Meeting Summary Generator&lt;br&gt;
 AI Form Auto-Fill Assistant&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The &lt;strong&gt;Vercel AI SDK&lt;/strong&gt; is one of the fastest ways to build AI apps with excellent streaming UX and clean developer experience.&lt;/p&gt;
&lt;p&gt;If you’re building in &lt;strong&gt;Next.js&lt;/strong&gt;, this is a must-try toolkit.&lt;/p&gt;
&lt;p&gt;Note: Create agents using Vercel&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://emilyxiong.medium.com/create-an-ai-agent-with-vercel-ai-sdk-e690b807eb2a&quot;&gt;https://emilyxiong.medium.com/create-an-ai-agent-with-vercel-ai-sdk-e690b807eb2a&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/10167/getting-started-with-the-vercel-ai-sdk-beginner-to-working-chat-app</guid>
<pubDate>Wed, 21 Jan 2026 12:44:06 +0000</pubDate>
</item>
<item>
<title>Deploy your application on Vercel with GitHub Actions</title>
<link>https://coderlegion.com/4878/deploy-your-application-on-vercel-with-github-actions</link>
<description>&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=5202709586993786117&quot; alt=&quot;&quot;&gt;&lt;br&gt;
A very common CI/CD pattern for frontend apps is: &lt;strong&gt;build in CI and deploy to production automatically when the code reaches&lt;/strong&gt; &lt;code&gt;main&lt;/code&gt;.&lt;br&gt;
If you use Vercel, you can do this with a &lt;strong&gt;short and reliable&lt;/strong&gt; GitHub Actions workflow that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;downloads your project's configuration and variables from Vercel,&lt;/li&gt;
&lt;li&gt;builds the app in CI,&lt;/li&gt;
&lt;li&gt;and deploys the already built artifacts to &lt;strong&gt;production&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this article, we'll walk through it step by step and I'll give you some tips to help you understand &lt;strong&gt;what each line does&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id=&quot;purpose-of-the-workflow&quot;&gt;Purpose of the workflow&lt;/h4&gt;
&lt;p&gt;Every time there is a push to &lt;code&gt;main&lt;/code&gt;, the following should be executed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pull config&lt;/strong&gt; from Vercel (includes &lt;strong&gt;production&lt;/strong&gt; environment variables).&lt;/li&gt;
&lt;li&gt;Reproducible &lt;strong&gt;build&lt;/strong&gt; in CI.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy&lt;/strong&gt; that artifact (without rebuilding in Vercel).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This will give you &lt;strong&gt;predictable&lt;/strong&gt; deployments that are easy to audit and debug.&lt;/p&gt;
&lt;h4 id=&quot;general-workflow-structure&quot;&gt;General workflow structure&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: Vercel PRO deployment
on:
  push:
    branches:
      - main
jobs:
  deploy:
    name: deploy
    runs-on: ubuntu-latest
    steps:
      - id: checkout-step
        name: Checkout code
        uses: actions/checkout@v4
      - id: install-vercel-cli-step
        name: Install Vercel CLI
        run: npm install --global vercel@latest
      - id: pull-vercel-env-info-step
        name: Pull Vercel Environment Information
        run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN
          }}
      - id: build-vercel-artifacts-step
        name: Build Project Artifacts
        run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
      - id: deploy-vercel-artifacts-step
        name: Deploy Project Artifacts to Vercel
        run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;br&gt;
Create the secret &lt;code&gt;VERCEL_TOKEN&lt;/code&gt; in your repository (Settings → Secrets and variables → Actions).&lt;br&gt;
Either commit &lt;code&gt;.vercel/project.json&lt;/code&gt;, or provide &lt;code&gt;VERCEL_ORG_ID&lt;/code&gt; and &lt;code&gt;VERCEL_PROJECT_ID&lt;/code&gt; as secrets when you do vercel pull.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;step-by-step&quot;&gt;Step by step&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;on: push (to main)&lt;/strong&gt;&lt;br&gt;
Each push to &lt;code&gt;main&lt;/code&gt; triggers the production pipeline. If you prefer to only deploy when merging by PR, simply avoid pushing directly to &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;uses: actions/checkout@v4&lt;/strong&gt;&lt;br&gt;
Download your code to the runner so that the following tools (Vercel CLI) have it available.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;npm install --global vercel@latest&lt;/strong&gt;&lt;br&gt;
Install the Vercel CLI.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; to avoid surprises, you can set version: vercel@xx (or whatever you use on your team).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;vercel pull --yes --environment=production&lt;/strong&gt;&lt;br&gt;
Bring the project configuration and production environment variables to &lt;code&gt;.vercel/&lt;/code&gt; on the runner.&lt;br&gt;
In CI there are no interactive questions, so we use &lt;code&gt;--yes&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.vercel/project.json&lt;/code&gt; in the repository or&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VERCEL_ORG_ID&lt;/code&gt; and &lt;code&gt;VERCEL_PROJECT_ID&lt;/code&gt; as variables/secrets.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;vercel build --prod&lt;/strong&gt;&lt;br&gt;
Builds in CI using your framework (Next.js, SvelteKit, etc.) or what is defined in &lt;code&gt;vercel.json&lt;/code&gt;.&lt;br&gt;
The result is stored in &lt;code&gt;.vercel/output&lt;/code&gt; and is exactly what you are going to deploy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;vercel deploy --prebuilt --prod&lt;/strong&gt;&lt;br&gt;
Uploads the already built artifact to production.&lt;br&gt;
With &lt;code&gt;--prebuilt&lt;/code&gt;, Vercel does not rebuild: what you tested in CI is what your user will see.&lt;/p&gt;
&lt;h4 id=&quot;-final-result&quot;&gt;✅ Final result&lt;/h4&gt;
&lt;p&gt;With this workflow, each merge to &lt;code&gt;main&lt;/code&gt; runs a clean build and deploys that same artifact to production in Vercel. You get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;reproducible builds,&lt;/li&gt;
&lt;li&gt;faster deploys,&lt;/li&gt;
&lt;li&gt;and clear CI logs for debugging.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;prefer-to-configure-it-visually-&quot;&gt;Prefer to configure it visually?&lt;/h4&gt;
&lt;p&gt;Writing workflows by hand gives you total control, but sometimes you want speed with built-in validations.&lt;/p&gt;
&lt;p&gt;With &lt;strong&gt;OctoLab&lt;/strong&gt;, you can set up this same pipeline visually: choose actions, fill in fields, and the YAML is generated instantly, ready to commit.&lt;/p&gt;
&lt;p&gt;Try it out: &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.octolab.app/templates/vercel-pro-deployment&quot;&gt;https://www.octolab.app/templates/vercel-pro-deployment&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;conclusion-1&quot;&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;This workflow provides you with a clean &lt;strong&gt;CI → production&lt;/strong&gt; flow on every push to &lt;code&gt;main&lt;/code&gt;, using Vercel's recommended approach: &lt;strong&gt;pull → build → deploy&lt;/strong&gt;. It's easy to adapt to previews, monorepos, or strict reproducibility (fixed Node and CLI). &lt;/p&gt;
&lt;p&gt;Use it as a base and evolve it with caching, notifications, or environment gates as your team grows.&lt;/p&gt;
</description>
<category>Getting Started</category>
<guid isPermaLink="true">https://coderlegion.com/4878/deploy-your-application-on-vercel-with-github-actions</guid>
<pubDate>Wed, 20 Aug 2025 17:26:29 +0000</pubDate>
</item>
<item>
<title>Use your custom 404 component on Vercel — Easy Fix</title>
<link>https://coderlegion.com/4408/use-your-custom-404-component-on-vercel-easy-fix</link>
<description>&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:720/format:webp/1*o56p3xlI73z3a7R2cytaTg.jpeg&quot; alt=&quot;&quot;&gt;&lt;br&gt;
I had just deployed a React application to Vercel, complete with routing and a custom &lt;em&gt;404&lt;/em&gt; error page. I tested the live site in Vercel and tried visiting a non-existent route, but I couldn’t! Vercel’s default 404 page was rendered instead of my custom component.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Here’s how I fixed it&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I needed to find a way to overwrite the default action by Vercel, so I conducted some research. So here’s what was happening - Vercel served its own 404 page &lt;em&gt;before&lt;/em&gt; my React app loaded.&lt;/p&gt;
&lt;p&gt;To fix this, first create a vercel.json file. Use the following code snippet in your file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;rewrites&quot;: [
    { &quot;source&quot;: &quot;/(.*)&quot;, &quot;destination&quot;: &quot;/&quot; }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That was it! I redeployed the application, and now my 404 component was rendered instead of the default one from Vercel.&lt;/p&gt;
&lt;p&gt;I hope this solution helped you. If so, please leave a comment below.&lt;/p&gt;
&lt;p&gt;Thanks for reading, &lt;em&gt;ciao&lt;/em&gt; &lt;/p&gt;
&lt;p&gt;&lt;em&gt;P.S. If your cursor starts acting up in VS Code, &lt;a rel=&quot;nofollow&quot; href=&quot;https://medium.com/@theambi/vs-code-cursor-problem-why-its-deleting-instead-of-inserting-text-fad546c6ca98&quot;&gt;check out this article&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</description>
<category>Web Dev</category>
<guid isPermaLink="true">https://coderlegion.com/4408/use-your-custom-404-component-on-vercel-easy-fix</guid>
<pubDate>Sun, 03 Aug 2025 22:33:07 +0000</pubDate>
</item>
</channel>
</rss>