Incremental EAS Hosting changes: May 2025
May 27, 2025 by

Phil Pluckthun

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 linkstaging.yourdomain.com
directly into EAS HostingCNAME www.<yourdomain> origin.expo.app
sets up a redirect to your custom domain automatically (as long as no alias namedwww
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:
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:
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"
.
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
andexpo 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--staging
→ myapp--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 forWeakRef
andFinalizationRegistry
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.