
I flere år var Vercel standardplattformen der vi publiserte nesten alt på nettet hos WebCatalog. De fleste av disse prosjektene brukte Next.js, så kombinasjonen var naturlig. Markedsføringsnettstedene, produktgrensesnittene, kontoinnstillingene, utviklerkonsollen, autentiseringen, administrasjonsverktøyene og API-ene våre endte alle opp på omtrent samme teknologistabel.
Det fungerte godt lenge. Vercel gjorde publisering enkelt, Next.js ga oss et produktivt fullstack-rammeverk, og vi trengte sjelden å tenke på infrastrukturen under noen av dem.
Etter hvert passet ikke denne bekvemmeligheten like godt til produktene våre lenger.
Markedsføringsnettstedene våre hadde fortsatt nytte av SSR (gjengivelse på serversiden), men de fleste andre nettappene våre hadde ikke det. De kunne være vanlige SPA-er (ensidesapplikasjoner). API-ene våre trengte et vanlig Node.js-miljø med native avhengigheter og langvarige prosesser. Nesten alt annet i frontend-stabelen vår brukte allerede Vite. Samtidig ble det stadig vanskeligere å overse infrastrukturkostnadene, særlig etter hvert som offentlig og automatisert trafikk økte.
Først prøvde vi å optimalisere det vi allerede hadde. Vi vurderte å beholde Next.js og flytte det til Cloudflare Workers gjennom en adapter. Vi prøvde Astro for markedsføringsnettstedene. En kort periode kjørte vi API-ene våre på Cloudflare Containers.
Til slutt landet vi på noe enklere: De fleste nettappene våre bruker nå Vite + TanStack Router på Cloudflare Workers, markedsføringsnettstedene våre bruker TanStack Start med SSR på Cloudflare Workers, og API-ene våre bruker Hono + tRPC på Railway som langvarige Node.js-containere.
Migreringen reduserte kostnadene for nettinfrastrukturen vår med omtrent 80 %. Etter at vi også strammet inn sikkerhetsreglene i Cloudflare og blokkerte mer fiendtlig automatisert trafikk i nettverkskanten, økte de samlede besparelsene til rundt 90 %.
Det meste av implementeringsarbeidet i migreringen ble også utført av AI-kodeagenter, hovedsakelig Claude Fable 5 og Claude Opus 5, mens utviklerne bestemte arkitekturen, definerte rammer, gjennomgikk endringer og verifiserte resultatet.
Vi begynte ikke med å forlate Vercel
Den første innskytelsen vår var å optimalisere det eksisterende oppsettet.
webcatalog.io var det mest opplagte stedet å starte, fordi nettstedet får mye offentlig trafikk, mens de fleste sidene endres relativt sjelden. Vi fant ut at for mye av nettstedet fortsatt ble gjengitt dynamisk. Derfor rettet vi opp utilsiktet dynamisk gjengivelse, la til ISR (inkrementell statisk regenerering) på ruter med mye trafikk, gjorde flere sider mulig å hurtigbufre og optimaliserte ressurskrevende behandling av nettstedskart.
Arbeidet hjalp, men gjorde også det underliggende problemet tydeligere. Vi brukte stadig mer tid på å forstå hvorfor relativt statisk innhold var dynamisk, hvilken oppførsel i rammeverket som forårsaket det, og hvilken mekanisme i rammeverket vi måtte ta i bruk for å kunne hurtigbufre innholdet igjen.
Samtidig hadde mange av de andre applikasjonene våre det motsatte problemet. Kontoinnstillinger, utviklerkonsollen, administrasjonsapper og de fleste produktgrensesnittene trengte ikke gjengivelse på serversiden i det hele tatt. De var nettleserapplikasjoner som kommuniserte med API-er.
Da sluttet spørsmålet å være «Hvordan gjør vi Vercel-regningen mindre?» og ble i stedet «Hva ville vi bygget hvis disse applikasjonene ikke allerede var Next.js-applikasjoner?»
Vi vurderte Next.js på Cloudflare
Det minst inngripende alternativet var å beholde Next.js og flytte det fra Vercel til Cloudflare Workers.
Vi vurderte dette seriøst, fordi Next.js kan kjøre på Cloudflare gjennom adapterlag. Det ville latt oss bevare mye av den eksisterende applikasjonsstrukturen.
Men vi anså ikke Next.js på Cloudflare som det samme som Next.js på Vercel. Next.js er tettest integrert med Vercels kjøremiljø, publiseringssystem, hurtigbufringsatferd og plattformfunksjoner. På Cloudflare må en adapter oversette disse forutsetningene til et annet kjøremiljø.
Det kan fungere godt, men hvis målet var å forenkle stabelen, virket det ikke ideelt å legge til enda et kompatibilitetslag.
Det var også et bredere spørsmål om verktøy. Nesten alt annet vi bygget på frontend-siden, brukte allerede Vite: skrivebordsapplikasjoner, nettleserutvidelser, SPA-er og andre prosjekter på klientsiden.
Next.js hadde beveget seg sterkt i retning av Turbopack, og Turbopack har blitt mye bedre. Dette handlet ikke om ytelse. For oss var økosystemet den viktigere forskjellen. Vite var allerede det felles grunnlaget for det meste av frontend-kodebasen vår, med et større økosystem av programtillegg og konfigurasjon som lettere kunne gjenbrukes på tvers av prosjekter.
Å beholde Next.js på Cloudflare ville dermed ha løst deler av vertsproblemet, men det ville ha videreført både misforholdet mellom rammeverkene og et separat økosystem for byggeverktøy.
Derfor tok vi et skritt tilbake og så på hva hver arbeidslast faktisk trengte.
Vi delte stabelen etter arbeidslast
Da vi sluttet å lete etter én universell erstatning for Next.js, ble arkitekturen mye enklere.
Markedsføringsnettstedene våre trengte SSR fordi de har offentlige, lokaliserte sider, metadata, kanoniske URL-er, nettstedskart og trafikk fra søkemotorer.
De fleste andre nettappene våre trengte ikke SSR og kunne ganske enkelt være Vite-applikasjoner med TanStack Router.
API-ene våre trengte ikke noe React-rammeverk i det hele tatt og passet bedre i et vanlig Node.js-kjøremiljø.
Den endelige inndelingen så slik ut:
Nettapper
Vite + TanStack Router
│
└── Cloudflare Workers
Markedsføringsnettsteder
TanStack Start + SSR
│
└── Cloudflare Workers
API-er
Hono + tRPC
│
└── Railway / Node.js-containere
Regelen ble enkel: Bruk SSR der det gir reell verdi, bruk en vanlig SPA der det ikke gjør det, og kjør backend-tjenester i et kjøremiljø for backend.
De fleste nettappene ble SPA-er
SPA-migreringene var den enkleste delen.
WebCatalog-nettappen ble flyttet spesielt raskt: Vi satte opp erstatningen med Vite + TanStack Router, porterte grensesnittet, flyttet publiseringen til Cloudflare Workers og fjernet den gamle Next.js-versjonen i løpet av samme formiddag.
Vi gjentok det samme mønsteret for Lexibird-nettappen, kontoinnstillinger, utviklerkonsollen, autentisering og administrasjonsapper. Fra vi satte opp den første SPA-en til vi slettet den siste Next.js-applikasjonen, tok det omtrent 19 dager.
For disse applikasjonene er Cloudflare Workers bevisst ukomplisert. Vite bygger statiske filer, Cloudflare leverer dem, og applikasjonsruter faller tilbake til index.html. Det finnes ikke noe SSR-kjøremiljø, fordi ingenting trenger å gjengis på serversiden.
Den vanskeligere delen var å bevare funksjonaliteten som hadde bygget seg opp rundt disse applikasjonene over tid. Noe autentiseringslogikk måtte flyttes ut av Next.js-serverruter og inn i API-et, og eldre versjoner av WebCatalog-skrivebordsappen var fortsatt avhengige av eldre endepunkter som vi måtte holde i drift.
Det var enkelt å flytte React-grensesnittet.
Det var vanskeligere å bevare kontraktene.
Vi prøvde Astro og slettet det fem dager senere
Markedsføringsnettstedene var vanskeligere.
Førstevalget vårt var Astro, som virket som en naturlig løsning for webcatalog.io og lexibird.com fordi begge er offentlige nettsteder med mye innhold, og Astro integreres godt med Cloudflare.
Vi begynte å portere begge nettstedene, og fem dager senere stoppet vi.
Det var ingen enkelt feil som felte løsningen. I stedet hopet små misforhold seg opp. Noen ruter trengte databasetilgang under forhåndsgjengivelse, mens byggemiljøet vårt med hensikt ikke hadde tilgangsinformasjon til produksjonsdatabasen. React-øyer gjorde delt applikasjonstilstand mindre naturlig. Vi støtte også på forskjeller mellom forhåndsgjengitte ruter og ruter som ble gjengitt under kjøring, samt noe friksjon med verktøyene i kodebasen vår.
Ingen av disse problemene var umulige å løse. Det var nettopp derfor det var risikabelt å fortsette. Vi kunne lett ha brukt enda noen uker på å løse det ene problemet etter det andre.
I stedet slettet vi implementeringen og begynte på nytt.
AI-agenter endret kostnadsbildet for den beslutningen. Mye av det mekaniske porteringsarbeidet hadde ikke krevd ukevis med utviklertid, så den allerede investerte innsatsen var mindre. Det gjorde det lettere å innrømme at vi foretrakk en annen arkitektur.
TanStack Start passet bedre
Vi startet migreringen av markedsføringsnettstedene på nytt fra den opprinnelige Next.js-koden, denne gangen med TanStack Start.
Det passet mye mer naturlig fordi vi allerede brukte TanStack Router i SPA-applikasjonene. Dermed fulgte ruting, lastere, søkeparametere og navigasjon lignende konsepter. Koden forble vanlig React og TypeScript, og byggesystemet var Vite.
Vi porterte lexibird.com til TanStack Start på én dag. Deretter fulgte webcatalog.io.
Fordelen var ikke at TanStack Start på magisk vis løste alle problemer. Fordelen var at det passet med retningen resten av stabelen vår allerede beveget seg i.
I et monorepo betyr det mye. Felles byggeverktøy gir flere programtillegg og konfigurasjoner som kan gjenbrukes, færre særtilfeller ved feilsøking, mindre kontekstbytte for utviklere og færre prosjektspesifikke konvensjoner som kodeagenter må finne ut av.
Cloudflare var mye billigere for trafikken vår
Arkitekturen var bare én av grunnene til at regningen gikk ned. Cloudflares prismodell var en viktig faktor, særlig når det gjaldt båndbredde.
Cloudflare Workers Paid tar for tiden hovedsakelig betalt for forespørsler og CPU-bruk og legger ikke til kostnader for dataoverføring eller båndbredde for Workers. (developers.cloudflare.com) Det betyr mye for offentlige nettsteder, fordi en forespørsel kan bruke svært lite CPU samtidig som den overfører HTML, JavaScript, bilder, skrifttyper og andre ressurser.
Vercels prismodell omfatter også bruks- og kvotekategorier knyttet til nettverk, blant annet Fast Data Transfer og Fast Origin Transfer. (vercel.com) For trafikkprofilen vår var Cloudflare betydelig gunstigere økonomisk.
Besparelsene kom ikke bare av å bytte leverandør. Vi flyttet også mange applikasjoner til statiske Vite-bygg, reduserte unødvendig SSR, gjorde hurtigbufring mer eksplisitt og flyttet API-arbeidslaster til et kjøremiljø som passet dem bedre. Men Cloudflares prismodell, særlig for båndbredde, bidro vesentlig til reduksjonen på omtrent 80 % som vi så.
Dette tallet gjelder vår arbeidslast. Det er ikke en påstand om at alle applikasjoner som flyttes fra Vercel til Cloudflare, vil spare 80 %.
API-ene endte opp på Railway
API-ene var et eget problem.
Selv om de var Next.js-prosjekter, var de allerede for det meste uavhengige av Next.js. WebCatalog-API-et besto av omtrent 34 000 kodelinjer, men bare sju filer importerte next/server. tRPC brukte allerede sin Fetch-adapter, og Inngest støttet Hono.
Vi erstattet Next.js-laget som håndterte HTTP, med Hono. Den delen var overraskende liten.
Det vanskeligere spørsmålet var hvor det skulle kjøres. Vanlige Workers passet ikke godt, fordi API-ene bruker Node.js og native avhengigheter som sharp.
Først prøvde vi Cloudflare Containers, som raskt fikk oss bort fra Vercel. Men etter å ha kjørt dette oppsettet i produksjon fant vi ut at driftsmodellen krevde mer manuell kapasitetsjustering enn vi ønsket på det tidspunktet.
Så vi flyttet API-ene igjen.
I dag kjører de på Railway som vanlige, langvarige Node.js-containertjenester. CI (kontinuerlig integrasjon) bygger Docker-avbildninger, sender dem til containerregisteret vårt, og Railway håndterer horisontal automatisk skalering.
Ikke alt trenger å kjøre i nettverkskanten.
Å forlate Vercel innebar mer ansvar
Den lavere kostnaden kom med en avveining.
Vercel og Next.js hadde håndtert mange infrastrukturfunksjoner på et høyere nivå. Med TanStack Start og Workers gikk vi i stedet over til eksplisitt HTTP-hurtigbufring. En side gjengis, vi returnerer hurtigbuffer-headere, og Cloudflare hurtigbufrer svaret. Nettleseren og nettverkskanten kan ha ulike regler for hurtigbufring, blant annet at nettverkskanten kan levere en foreldet versjon mens den oppdateres.
Vi likte at disse beslutningene ble eksplisitte, men eksplisitt infrastruktur betyr også at feilene er dine egne.
Vi gjorde noen feil. Én hurtigbufferregel i produksjon fanget ved et uhell opp besøksspesifikke svar fra TanStack-serverfunksjoner, og en annen hurtigbufferkonfigurasjon fungerte dårlig sammen med reservehåndteringen for SPA-ruter. Disse feilene var nyttige påminnelser om at man ikke kan bevise at en migrering er korrekt bare ved å se på kodebasen. Produksjonsinfrastrukturen er også en del av systemet.
AI-agenter endret måten vi migrerte på
Det meste av implementeringsarbeidet ble utført av kodeagenter, hovedsakelig Claude Fable 5 og Claude Opus 5.
Rammeverksmigreringer egner seg uvanlig godt for agenter, fordi mye av arbeidet har en tydelig eksisterende referanse: Flytt denne ruten, bevar denne URL-en, erstatt dette rammeverks-API-et, behold de samme metadataene, kjør typesjekk, rett feilene og sammenlign resultatet med den gamle implementeringen.
For webcatalog.io førte vi en oversikt over migreringen som delte arbeidet inn i faser som grunnlag, produktsider, katalogsider, søk, blogg, priser, omdirigeringer, nettstedskart og overgang til den nye løsningen. I stedet for å be en agent om å «migrere webcatalog.io til TanStack Start», ga vi den avgrensede oppgaver med tydelige krav til hva som måtte forbli uendret.
Den eksisterende applikasjonen ble spesifikasjonen. Agentens oppgave var å gjenskape funksjonaliteten med den nye arkitekturen, ikke å finne opp produktet på nytt.
Det flyttet menneskenes innsats bort fra å oversette kode manuelt og over til spørsmål som: Bør denne siden egentlig bruke SSR? Hvilken oppførsel er tilsiktet? Hva kan hurtigbufres globalt? Hvilke URL-er må forbli identiske? Hvor bør autentisering skje? Når bør vi slutte å prøve å få en tilnærming til å fungere?
Vi gjennomgikk fortsatt resultatet, kjørte bygg og typesjekker og verifiserte manuelt områder med høyere risiko, som autentisering, SEO (søkemotoroptimalisering), omdirigeringer og hurtigbufring.
Den viktige endringen var ikke at AI skrev kode for oss. Det var at AI gjorde det billigere å eksperimentere.
Det ble mye lettere å forsvare å prøve Astro og slette det etter fem dager. Det var mindre smertefullt å flytte API-ene én gang og deretter bestemme at en annen plattform passet bedre. Det mekaniske arbeidet kostet mindre, så vi kunne endre kurs når arkitekturen var feil, i stedet for å fortsette fordi vi allerede hadde investert for mye i den.
Agenter gjorde implementeringskapasitet mindre knapp.
Det gjorde arkitektur, rammer, gjennomgang og verifisering viktigere.
80 % ble til omtrent 90 %
Etter migreringen var kostnadene for nettinfrastrukturen vår omtrent 80 % lavere.
Deretter begynte vi å følge bedre med på hvilke forespørsler som i det hele tatt nådde applikasjonene.
En betydelig del av trafikken på det åpne nettet er automatisert: søkemotorer, AI-indekseringsroboter, agenter, skrapere, skannere og mindre vennligsinnede roboter. Noe av denne trafikken er nyttig, og noe er det ikke.
Med applikasjonene rett bak Cloudflare strammet vi inn sikkerhetsreglene, slik at fiendtlig automatisert trafikk kunne avvises i nettverkskanten før den utløste beregninger i applikasjonene eller databasearbeid.
Etter dette nådde de samlede besparelsene våre omtrent 90 % sammenlignet med det gamle oppsettet.
Den endelige reduksjonen skyldtes flere faktorer som virket sammen: Cloudflares lavere priser, særlig på båndbredde; mindre arbeid på serversiden; et bedre kjøremiljø for API-ene våre; mer eksplisitt hurtigbufring; og færre unødvendige forespørsler som i det hele tatt nådde applikasjonene.
Der vi endte opp
Det finnes ingen Next.js-applikasjoner igjen i kodebasen vår. De fleste nettappene våre er nå SPA-er med Vite + TanStack Router på Cloudflare Workers. webcatalog.io og lexibird.com bruker TanStack Start på Cloudflare Workers, fordi disse nettstedene faktisk har nytte av SSR. API-ene våre bruker Hono + tRPC på Railway og kjører som vanlige Node.js-containere. Nesten alle frontend-prosjektene våre er nå en del av Vite-økosystemet.
Infrastrukturkostnadene våre falt med omtrent 80 %, i stor grad takket være at Cloudflare er betydelig gunstigere for trafikken vår, særlig når det gjelder båndbredde. Filtrering av fiendtlig automatisert trafikk i nettverkskanten økte de samlede besparelsene til rundt 90 %.
Men resultatet vi er mest opptatt av, er arkitekturen. Markedsføringsnettstedene får SSR, alt annet som kan være en SPA, er en SPA, og API-er kjører på ordentlige servere når ordentlige servere er den enkleste løsningen.
Vi begynte med å prøve å gjøre Vercel billigere.
Vi endte med å innse at vi ikke trengte mesteparten av arkitekturen vi betalte for.