Incremental EAS Hosting changes: May 2025

May 27, 2025 by

Phil Pluckthun

Phil Pluckthun

Incremental EAS Hosting changes: May 2025

EAS Hosting’s updates ship incrementally without versioning and are backwards compatible. Runtime changes will require you to re-deploy with eas deploy while network and CDN changes apply automatically.

Wildcard custom domains

We’ve received several requests to add support for subdomains on EAS Hosting’s custom domains, and support for www subdomains specifically. We’re happy to report that this has now been implemented.

Once you’ve clicked “Refresh” in the EAS Hosting settings’ “Custom domains” section, you’ll now be able to set up subdomain records for your custom domain, for example:

  • CNAME <alias>.<yourdomain> origin.expo.app sets up a subdomain for a named alias, so you can for example link staging.yourdomain.com directly into EAS Hosting
  • CNAME www.<yourdomain> origin.expo.app sets up a redirect to your custom domain automatically (as long as no alias named www exists)
  • CNAME *.<yourdomain> origin.expo.app sets up a wildcard for all aliases in your project

Note that we still only support one custom domain per project. But we hope that the support for wildcard subdomains on this custom domain will alleviate the need to set up multiple custom domains per project.

Learn more about how to set up the new DNS records in our docs: https://docs.expo.dev/eas/hosting/custom-domain/#alias-and-wildcard-subdomains

Notice: Custom Domain CNAMEs are changing

Instead of fallback.expo.app we now recommend you to set up CNAMEs for your custom domains with the origin.expo.app value instead.

origin.expo.app itself is a CNAME that links to fallback.expo.app . This is mainly an internal change that allows us to change what origin.expo.app points to in case we need to make changes to our internal CDN configuration.

No changes are required immediately if you’ve already set up a custom domain. fallback.expo.app will continue to work for the foreseeable future, and we recommend you to switch over this value within the next 6 months.

If we decide to shut down fallback.expo.app as a valid value, we’ll send out repeated notices before doing so, but we don’t have any immediate plans to force a switchover yet.

Worker Deployment File Browsers

The dashboard’s worker deployments details page now displays file trees both for your deployments’ server code and client assets. We felt that having a file browser to quickly see what past deployments contain is crucial and we’ll be adding more details and information to this page in the future.

Request logs record Expo routes and pathnames

Previously, our request logging didn’t record both pathnames and Expo Router route names. Instead, it could only record and display one at a time.

This was especially obvious with React Server Component requests always displaying /_flight/[...rsc] for many requests and entries.

Instead, our logging now records route parameters as well, when we’ve detected that a request is being made to an Expo Router API route, which means that the dashboard now displays both the full original path as well as the Expo Router route.

Here we see a request to the exported RSC route, /_flight/[...rsc], is being expanded to show the request’s deep route parameter, /web/ACTION_./actions/render-info.tsx/default.txt.

New Hosting Overview

An improved at-a-glance dashboard for how your project is doing.

This also enables new request filters: by platform and country.

Improved request header URLs

When a complex app is deployed with many different aliases, a custom domain, and environments, it was previously tricky to write code that reacts to these changing request origins.

For example, previously, when a request is made to a worker deployment https://myapp--staging.expo.app/api/route, the API route would mostly only see its own URL even if the client made a request to an alias URL or a custom domain:

Terminal
GET https://myapp--id.expo.app/api/route Host: myapp--id.expo.app Forwarded: for=1.2.3.4;proto=https X-Forwarded-For: 1.2.3.4 X-Forwarded-Proto: https X-Real-IP: 1.2.3.4

In the previous request headers, no headers or hints were available for the incoming request’s URL and only the outgoing one. Hence, it was impossible to write conditional logic for requests being made to custom domains, for instance.

We’ve updated these headers and they now reflect both the incoming origin URL and the target URL separately:

Terminal
GET https://myapp--id.expo.app/api/route Host: myapp--id.expo.app Origin: https://myapp--staging.expo.app Forwarded: for=1.2.3.4;host="myapp--staging.expo.app";proto=https X-Forwarded-Host: myapp--staging.expo.app X-Forwarded-For: 1.2.3.4 X-Forwarded-Proto: https X-Real-IP: 1.2.3.4

As seen above, although the request to myapp--staging.expo.app resolves to myapp--id.expo.app, the Origin, Forwarded, and X-Forwarded-Host headers now reflect the incoming URL’s hostname instead.

New origin global

To complement this change, the origin global was updated to output the current request URL’s Origin per request. Previously, this property would always be set to "null".

Code
export async function GET(request) {
console.log(origin); // 'https://myapp--staging.expo.app'
}

It now outputs the current request URL’s origin, depending on the ongoing request, dynamically, and should always be identical to request.headers.get('Origin').

⚠️ This global is only available in EAS Hosting worker deployments. expo start and expo serve currently stick to a plain Node.js environment and won’t emulate it.

Support for 404.html for static deployments

Not all static site generators follow the same output conventions. While Expo Router’s static output generates +not-found.html files for “404 Not Found” pages, other static-site generators prefers to output 404.html files.

To help with making EAS Hosting useful for static sites that aren’t generated with Expo Router, we now support the 404.html output variants as well.

A static deployment is only expected to either use +not-found.html pages or 404.html pages for not-found pages, but not both at the same time. While deploying, EAS Hosting will detect and decide which one it’ll use ahead of time.

Fix for HEAD requests to assets

We’ve noticed that HEAD requests made to assets weren’t resolving correctly, and would instead result in 404 responses, even if the path matches an asset’s path.

This is now fixed and working as intended.

Fix for the agentkeepalive package

Previously, due to options: AgentOptions; not being present on node:http's Agent class, the agentkeepalive package wasn’t functional and would throw a runtime error.

This has now been fixed and the missing internal property has been added to our layer of Node polyfills.

Streamed worker deployments

The size limit for worker deployments is generally 10MiB (gzip compressed) for all server files combined. When this size is exceeded by your upload, the worker deployment cannot be created and an error will be displayed by eas-cli.

However, this wasn’t always the case,

  • some worker deployments could cause our upload API to run out of memory, which prevented us from completing the deployment successfully
  • worker deployments exceeding 10MiB (gzipped) could cause our upload API to run out of memory as well, which prevented us from displaying an error message of what had happened

This has now been addressed by rewriting our upload API to be streamed. Instead of unpacking and handling your worker deployments in memory, it will now stream each part of the upload where it needs to go and prevent itself from running out of memory.

This has also made uploads more reliable and a little quicker.

Internal caching changes

All caching in EAS Hosting is namespaced per worker deployment. However, we also have layers of caching that apply to routing. For example, EAS Hosting will cache where a request to an alias (e.g. myapp--stagingmyapp--id) needs to go.

This meant that changing aliases, deleting aliases, deleting worker deployments, and promoting worker deployments to production was taking longer than expected.

We’re now proactively purging caches to prevent this, which should speed up all mentioned operations to complete much sooner. Often in a few seconds, and at most in a few minutes.

Added missing process.stdout and process.stderr normalization

In EAS Hosting, any library that writes to process.stdout and process.stderr is supported and their output will be redirected to the Console API. This means that common debugging packages outputs’ (such as debug's output) isn’t lost.

However, previously we weren’t splitting this terminal output into separate lines and ANSI escape codes weren’t removed. This could result in confusing logs being displayed in the EAS Hosting dashboard.

We’re now normalizing this output and it should be more readable now.

Cloudflare Worker runtime updates

The Cloudflare team has been hard at work to update their Node compatibility and to add more features to their runtime:

  • EAS Hosting’s WeakRef shim has now been replaced with native support for WeakRef and FinalizationRegistry
  • node:tls support has been added (for client requests only) and replaces the previous, non-functional EAS Hosting shim
  • The URLPattern web standard global is now supported

For more information on the latest runtime changes, check out Cloudflare’s workerd repository’s release notes.