The moment arrives in almost every Astro project. The website is finished, entirely static, loads fast, and then the contact form needs server-side validation, a price calculator needs to run live, or a customer area needs to sit behind a login. From that point on the project needs an adapter. And with the adapter comes a question far more consequential than the astro add command used to answer it.
I have taken the four usual routes apart. Not by deployment convenience, but by what applies permanently afterwards.
Four adapters, four different runtimes
astro add vercel, netlify, cloudflare or node look identical from the outside. Underneath, the code ends up in four fundamentally different environments.
As of 27 July 2026 the current versions are @astrojs/node 11.0.2, @astrojs/vercel 11.0.3, @astrojs/netlify 8.1.2 and @astrojs/cloudflare 14.1.5, all with the peer dependency astro ^7.0.0. Astro itself sits at 7.1.4 and requires Node 22.12.0 or newer.
Photo: eelias / Unsplash
The Node adapter has two modes. standalone starts its own HTTP server, middleware hooks into an existing Express or Fastify application. Configuration happens through environment variables.
// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
export default defineConfig({
adapter: node({ mode: 'standalone' }),
});
HOST=0.0.0.0 PORT=4321 node ./dist/server/entry.mjs
Cloudflare is the outlier. Since @astrojs/cloudflare 13.0.0 the official support for Cloudflare Pages has been removed, the changelog states “Drops official support for Cloudflare Pages in favor of Cloudflare Workers”. New projects go to Workers, and Workers do not run Node, they run workerd. Anyone using Node APIs, which most Astro projects do through their dependencies, needs a flag.
// wrangler.jsonc
{
"main": "@astrojs/cloudflare/entrypoints/server",
"name": "my-astro-app",
"compatibility_flags": ["nodejs_compat"],
"compatibility_date": "2024-09-23"
}
Without nodejs_compat there is no node:buffer, no node:crypto, no node:path and none of the rest. Astro sessions land in KV automatically on Cloudflare, and according to the documentation KV is only eventually consistent across regions, with up to 60 seconds until global propagation. For a shopping basket that matters, for a form endpoint it rarely does.
The cost lever sits before the platform choice
One misunderstanding costs more money than any platform decision. An adapter does not make an Astro project dynamic. The documentation is unambiguous: “By default, your entire Astro site will be prerendered, and static HTML pages will be sent to the browser.”
Server load only occurs where a route explicitly asks for it.
// This single line creates the bill. Not the adapter.
export const prerender = false;
For a company website that usually means the form endpoint and perhaps two API routes run server-side, while the remaining 40 pages are static HTML. Anyone who instead sets output: 'server' globally, because some tutorial said so, pays for every request to every subpage. That is the most expensive one-line mistake in this entire comparison.
What actually gets billed under SSR
The four routes bill by four different units, and that determines the traffic level at which it starts to hurt.
Vercel has moved billing from GB-seconds to three separate items. Active CPU only counts during actual code execution, Provisioned Memory runs continuously including during I/O waits, and invocations are charged on top. In Frankfurt (fra1) that comes to 0.184 USD per CPU hour and 0.0152 USD per GB hour of memory, plus 0.15 USD per GB of Fast Data Transfer above the first terabyte and 2.60 USD per million edge requests above the first ten million. The regional table names no price per invocation at all, the fluid pricing document works with 0.60 USD per million in a worked example. Builds cost 0.0035 USD per CPU minute. The Hobby plan with its one million invocations is explicitly described in the fair use policy as “non-commercial, personal use only”, so it is out of the question for a company website. Pro starts at 20 USD per month for one deploying seat, and every additional seat costs another 20 USD.
Netlify has billed in credits since 14 April 2026. Bandwidth is 20 credits per GB, compute 10 credits per GB hour, web requests 2 credits per 10,000, and a production deploy 15 credits. Netlify itself puts a dollar figure on this, turning 20 credits per GB into 0.13 USD. On that basis the 3,000 credits in the 20 USD Pro plan correspond to roughly 150 GB of pure bandwidth. The free plan has a hard ceiling of 300 credits with no option to top up, so roughly 15 GB. Deploy previews and branch deploys are free, and per-seat billing has been dropped.
Photo: towfiqu999999 / Unsplash
Cloudflare bills by CPU milliseconds. The free tier allows 100,000 requests per day at 10 ms of CPU time per invocation, the paid tier starts at 5 USD per month with 10 million requests and 30 million CPU milliseconds, and beyond that 0.30 USD per additional million requests. Requests to static assets are, according to the documentation, “free and unlimited”. For a mostly prerendered Astro site that is by far the cheapest arrangement. The limits are correspondingly hard: 128 MB per isolate, 3 MB gzipped worker size on the free plan, 10 MB on the paid plan.
With your own Node process, nothing is billed per request at all. A Hetzner CX33 with 4 vCPU and 8 GB has cost 8.49 euros per month since the price adjustment of 15 June 2026, including 20 TB of traffic and one IPv4 address. Whether the server handles 100 or 100,000 requests does not appear on the invoice.
All of these figures are list prices per unit, not observed invoices. Turning them into a forecast requires your own traffic data.
Cold start is not a number, it is an architecture
Plenty of cold start figures circulate, and most of them come from the providers themselves. I have measured nothing here, so I am sticking to what is documented.
Cloudflare uses V8 isolates instead of virtual machines. According to the documentation an isolate is created inside an already running environment, which “eliminates the cold starts of the virtual machine model” and starts roughly a hundred times faster than a Node process in a container. The Cloudflare blog puts loading a worker at 5 ms, and the start is triggered as early as the TLS ClientHello, so that it disappears into the network latency. That blog post dates from 30 July 2020, however, so it is old.
Vercel deliberately stays qualitative. Fluid compute has been the default for new projects since 23 April 2025, dampens cold starts through bytecode caching and pre-warming and “minimizes the effects of cold starts by greatly reducing their frequency and softening their impact”. Vercel names no milliseconds.
Netlify Edge Functions run in a Deno-based runtime with a limit of 50 ms of CPU execution time per request. That is not a cold start issue, but it hits Astro middleware directly as soon as middlewareMode: 'edge' is set.
The permanently running Node process does not have the problem at all. It starts once and stays up. That is the most straightforward advantage of running your own server, and the one mentioned least often.
The chain of processors is the real differentiator
This is where the four routes genuinely part ways, and it is the part most comparisons skip entirely.
Vercel Inc. is a Delaware company, and its DPA states that “Vercel’s primary processing facilities are in the United States”. The platform itself runs on someone else’s infrastructure, documented as “The Vercel CDN and deployment platform primarily uses Amazon Web Services (AWS)”. So there is at least one further processor attached. At Vercel the objection period for new sub-processors is five calendar days, and the only remedy is termination. The complete sub-processor lists for Vercel and Netlify sit behind trust centre logins and cannot be viewed without registering. For a record of processing activities under Art. 30 GDPR that is awkward.
Photo: drwmrk / Unsplash
Then there is the default region, which is easily overlooked. Vercel places the functions of all new projects in iad1, that is Washington D.C. Netlify functions run by default in cmh, US East in Ohio. Both can be changed, on Netlify only from the Pro plan upwards.
// vercel.json
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"regions": ["fra1"]
}
# netlify.toml
[functions]
region = "fra"
With Cloudflare Workers, regionalisation is practically impossible to achieve. The Data Localization Suite is an enterprise add-on, and for Workers the documentation says in any case that “Workers code and secrets are deployed globally to all Cloudflare data centers”. Regional Services only applies to the configured custom domain and does not cover outgoing subrequests, queues or cron triggers.
Hetzner sits at the other end. In its data processing agreement under Art. 28 GDPR, version 1.1 of 10 February 2025, section 3 paragraph 1 states verbatim that processing takes place “exclusively in a member state of the European Union or in another state party to the Agreement on the European Economic Area”. The approved sub-processors are tied to locations, Hetzner Finland Oy for Finland, Hetzner US LLC and two data centre operators for the United States. Anyone booking in Nuremberg or Falkenstein has Hetzner Online GmbH as the single processor. The objection period for a change of sub-processor is 14 days.
CLOUD Act and Data Privacy Framework, as of July 2026
All three US platforms are certified under the EU-U.S. Data Privacy Framework, and for Netlify the DPF list gives 13 February 2020 as the original certification date. That is a valid transfer mechanism based on adequacy decision (EU) 2023/1795 of 10 July 2023. It is not immunity from access under US law.
The US CLOUD Act sits in the statute book as 18 U.S.C. § 2713, inserted on 23 March 2018. The wording obliges providers to hand over content and customer data “regardless of whether such communication, record, or other information is located within or outside of the United States”. The server location is therefore the wrong question. What matters is which group owns the provider. Whether Vercel, Netlify and Cloudflare qualify as providers within the meaning of the Stored Communications Act in a given case has not been settled by a court, but in practice it is treated that way.
The situation is also in motion. The General Court dismissed the Latombe annulment action on 3 September 2025, and the appeal is pending before the Court of Justice as C-703/25 P. On 29 June 2026 the US Supreme Court held 6:3 in Trump v. Slaughter that removal protection for FTC commissioners is unconstitutional. noyb subsequently called on the European Commission to withdraw the adequacy decision in an orderly manner, because the Commission relies on an independent FTC in many places within it. Nothing has been revoked so far. Anyone looking for a forecast will not find one here. Anyone who needs a risk assessment for a record of processing activities has what they need in these facts.
Relevant as a side note: Cloudflare announced the acquisition of the Astro Technology Company on 16 January 2026. Since then the framework vendor and one of the four deployment options have belonged to the same group.
Your own Node process on Hetzner, with everything that comes with it
This website runs as an Astro SSR container with node dist/server/entry.mjs on port 4321, on a Hetzner CX33 in the Nuremberg data centre, orchestrated through Coolify, with Traefik as the reverse proxy and TLS via Let’s Encrypt. Around 36 containers run on the same server. Coolify is licensed under Apache License 2.0 and describes itself as “completely free to use, open-source, and has no features locked behind a paywall”, including push-to-deploy and PR deployments.
That sounds like the convenient option. It is not, and the evidence sits in my own operations notes.
On 25 July 2026, 616 never cleaned up Docker overlay2 layers filled the disk. The symptoms were HTTP 500 responses from the Coolify API and 350 percent CPU load. It was fixed by deleting logs, rebooting and running docker prune, which freed 11.18 GB. Disk usage afterwards was 83 percent. 80 GB for 36 containers is too tight, and a cron job for regular pruning is still missing to this day.
Photo: fslfsl / Unsplash
Second example. Coolify auto-deploy after git push does not reliably trigger for the website app, so the deployment has to be started through the API there. Third example. Docker only reads container labels on create, not on stop and start. Changed Traefik labels on a Node app only took effect after a full deploy, not after a restart. Fourth example. The noindex for staging domains is a Traefik label middleware with X-Robots-Tag in my setup, deliberately not in the code, so that no noindex travels along into a client deployment. On Vercel and Netlify exactly that is built in.
Persistent data is the fifth point. On your own server a volume is attached to the container and uploads simply sit there. On the serverless platforms this concept does not exist, and every file needs external object storage. That is not a disadvantage, but it is an architectural difference worth knowing before you choose.
And build times. On one of my Next.js projects on Coolify with Nixpacks, builds averaged 7 to 8 minutes before optimisation, the fastest 5m34s, the longest 12m14s (measured in early June 2026). In a bottleneck analysis of a seven minute build, 122 seconds went on the Docker export of the image layers alone and 40 seconds on the unpack, together 39 percent pure image handling. A standalone output, a .dockerignore and a dedicated nixpacks.toml are routine work by comparison, but finding and implementing them was still on me. You do not pay that time in dollars, but you do pay it. Astro itself is not the problem here, and the upgrade of this website to Astro 7 halved the build time.
A decision grid for small company websites
Four cases, four answers.
A mostly static company website with one form endpoint and no particular data protection requirements runs most cheaply on Cloudflare Workers. 5 USD per month, free asset requests, no cold start problem. Price and performance beat everything else here.
If that same website processes personal data that has to appear correctly in a record of processing activities, the picture flips. A short, documented chain then counts for more than three euros saved, and your own Node process at an EU provider is the clearer answer.
A team that has to ship quickly without in-house operations expertise and needs preview deployments per pull request is well served by Vercel or Netlify. But then with regions: ["fra1"] or region = "fra" respectively from the very start, not retrofitted later.
And anyone already running a server with other services on it has effectively made the decision already. The marginal effort for one more Astro container is small, the marginal effort for one more platform in the record of processing activities is not.
If you are facing exactly this decision and want to know which routes in your Astro project actually need to run server-side and what that means per platform, I am happy to look at it with you. Send me a short description of how the project is set up.
FAQ
Do I even need an adapter for Astro?+
Only if at least one route has to be rendered at request time, for example a form endpoint, a personalised page or an API route. Without an adapter, Astro builds plain static HTML that any web host can serve. With an adapter installed, everything still stays prerendered until a route explicitly sets `prerender = false`.
Is Cloudflare Workers cheaper than your own server for a company website?+
For a small, mostly prerendered site, usually yes. Workers Paid starts at 5 USD per month, and requests to static assets are free and unlimited according to the Cloudflare documentation. A Hetzner CX33 costs 8.49 euros per month plus the operational effort. The reason to run your own server is rarely the price, it is control over the chain of processors.
Is the EU-U.S. Data Privacy Framework enough as a legal basis?+
The adequacy decision (EU) 2023/1795 is in force as of July 2026, and Vercel, Netlify and Cloudflare are all certified. That is a valid transfer mechanism. It is not protection against access under US law, and the appeal against the General Court judgment in the Latombe case is pending before the Court of Justice as C-703/25 P.
What does Cloudflare acquiring Astro change for my project?+
Technically nothing so far. Cloudflare announced the acquisition of the Astro Technology Company on 16 January 2026, Astro remains open source, and the adapters for Node, Vercel and Netlify continue to be maintained. What matters for planning is that the framework vendor and one of the deployment options now belong to the same group.
Want to know more?
In a free intro call we discuss how you can use these topics for your company. Not a sales pitch, but an honest assessment.
Book a free intro call



