The Experience of Deploying Next.js Apps on Cloudflare

I recently went through the process of deploying various small Next.js applications to Cloudflare. As part of working on a new command called "neonctl create-app", we built a way to automatically deploy Next.js full-stack apps (i.e., Next.js apps with a backend+frontend) to both Cloudflare and Vercel. Besides this, I already had quite a bit of experience with deploying Next.js apps to Vercel.

I never expected the Cloudflare Pages experience to be as smooth as the Vercel experience. Afterall, Next.js is primarily developed by Vercel. However, given Next.js's popularity, I was a bit disappointed with Cloudflare's support for it.

In this blog post, I'll break down all of the issues I've found and how they could be improved.

Documentation for @cloudflare/next-on-pages is lacking

Cloudflare publishes a package called next-on-pages. It builds Next.js apps in such a way that they can then be deployed on Cloudflare Pages. You can read about what it does (and doesn't do) in the documentation.

However, the docs for how to use the package are very brief, and not integrated in the Cloudflare Docs platform (instead, it's a markdown file deep inside a GitHub repository). The discoverability for these docs is not great, and the actual build command (npx @cloudflare/next-on-pages@1) is very hard to find in this document.

wrangler pages dev is a bit confusing

At first, it was a bit unclear to me whether I'd need to run wrangler pages dev to start my app locally instead of next dev dev (the standard Next.js command which comes pre-configured when you use create-next-app). Eventually, I realized that npm run dev also works, but wrangler pages dev is a better simulation of how your app will actually run in the Cloudflare Pages platform. It also supports things such as as HTTPS for local development (basically like next dev --experimental-https).

In the docs, some differences between npm run dev and wrangler pages dev are mentioned, but it would be good to have a more exhaustive comparison.

.dev.vars is inconsistent with .env.local

Next.js automatically loads environment variables from a .env.local file, but with wrangler pages dev, you have to either:

  • Use .dev.vars
  • Add environment variables to wrangler.toml

I don't understand why Cloudflare would have this inconsistency — it only creates friction with the existing ecosystem. Furthermore, by putting variables in wrangler.toml, now you can't really commit this file in your repository (but most likely, one would want to commit it).

A change in the vercel CLI broke @cloudflare/next-on-pages for everyone

Last week, a change in the Vercel CLI (which is a dependency of @cloudflare/next-on-pages) broke building Next.js applications with at least with one static export (e.g., favicon.ico).

In my opinion, the @cloudflare/next-on-pages package needs to either:

  • Pin all of its dependencies
  • Have better end-to-end tests that are running against the latest (or even various) versions of its dependencies

To be fair, the bug was fixed quickly (~24 hours) and a new @cloudflare/next-on-pages release was shipped. However, this seems like the kind of thing that can happen again quite easily.

On Cloudflare deployments, I hit this issue where Set-Cookie in a HTTP response is not actually triggering all cookies to be set. The exact same code works fine in local development or in Vercel.

I believe this is a bug somewhere, and have tried to get some help:

As of the writing of this blog post, I have not yet figured this one out.

statusText in HTTP response not being returned

Another issue I hit exclusively on Cloudflare Pages deployments is that the statusText of a HTTP response is not making it to the client. I am fairly sure that this is because statusText is not really supported in HTTP/2. But, in my testing, it seems that both Cloudflare Pages and Vercel are on HTTP/2, so I wasn't able to confirm what's going on here.

Either way, I've learnt that using statusText is just not a good idea!

ERR_SSL_VERSION_OR_CIPHER_MISMATCH on new projects

Whenever I create a new Cloudflare Pages project, after the first deployment I get a ERR_SSL_VERSION_OR_CIPHER_MISMATCH error when loading the preview deployment. It takes around 15 minutes for this to go away.

Of course, this is not a big deal, but it's the kind of polish that's quite important to get right in developer tooling (I've never had this kind of problem with Vercel, it is superbly polished).

Node.js Compatibility (Workers)

So, I already knew that Cloudflare Workers (which power Cloudflare Pages Functions) are running on v8 Isolates, which makes them very cheap and very fast. It does come with a downside though, which is that not all of Node.js's features work.

This is a fine tradeoff. However, given how long Cloudflare Workers have been along, I expected the ecosystem to be on much better terms with this. It seems that a lot of popular NPM packages haven't been adapted to support Workers, and documentation is lacking, in general, when it comes to running many popular things on Workers.

It seems that Cloudflare should invest a lot more into making contributions to as many packages as possible such that deploying on Workers becomes easier for most people.

(One example I personally hit was password hashing. It was quite tricky to figure out how to use the Web Crypto API to do password hashing on Workers. I eventually found a great blog post on it though. However, I'm still not entirely sure that doing password hashing on Workers is a good idea at all.)

Logging Experience

Since I hit lots of problems, I had to read a lot of logs. However, finding logs was pretty though. The Cloudflare Dashboard is starting to suffer from many of the same UI/UX issues that the AWS Console is notorious for — trying to service too many different products, services and personas. (The Cloudflare Docs have the same problem since they have so many different products).

Once you do find the logs, you have to click "Record" to read them, so most of the time you need to replay whatever it is that you want to debug. I understand this might be a limitation of the free tier, which is fair, but it has not been an issue for me in Vercel.

I will add that if you use wrangler pages deployment tail, the logging experience is quite nice!

Summing Up

I genuinely want to see alternatives to Vercel flourish, as it'd be good for everyone in the ecosystem to push each other and compete for the hosting of Next.js applications. Both pricing and developer experience will play a big role here, of course.

I have been told that with services like Render, Fly.io, SST and Heroku, deploying Next.js apps is easier. However, I haven't tried those so I can't personally comment on them.

Finally, I hope this blog post makes its way to someone at Cloudflare as it may be useful for them as they decide what to work on.

Feel free to reach out on Twitter!