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.appsets up a subdomain for a named alias, so you can for example linkstaging.yourdomain.comdirectly into EAS HostingCNAME www.<yourdomain> origin.expo.appsets up a redirect to your custom domain automatically (as long as no alias namedwwwexists)CNAME *.<yourdomain> origin.expo.appsets 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.4In 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.4As 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 startandexpo servecurrently 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
WeakRefshim has now been replaced with native support forWeakRefandFinalizationRegistry node:tlssupport has been added (for client requests only) and replaces the previous, non-functional EAS Hosting shim- The
URLPatternweb standard global is now supported
For more information on the latest runtime changes, check out Cloudflare’s workerd repository’s release notes.