The third major release of Expo Router is now in beta for the next month. Expo Router v3 is part of Expo SDK 50 (React Native 0.73.0).
Expo Router v3 offers a new experimental system for building server endpoints: API Routes, reduced bundle size, and more powerful web support––we’re still on track to deliver full web support in v4.
The full release notes for Expo Router v3 won’t be available until the stable release, but you can browse the changes in the expo/expo CHANGELOG to learn more about the scope of the release and any breaking changes.
New Features
- 2x faster static website exports:
npx expo export -p webis over 2x faster. An average v2 project exported in ~23s, v3 exports in ~11s. These savings scale with the project! - 30% smaller base bundle size: The base bundle size for production websites is now 30% smaller (from 1.48mb to 1.05mb). The initial bundle size is further decreased by enabling the new bundle splitting functionality on web.
Press enter or click to view image in full size
- API Routes: Based on our API Routes RFC––This is a zero-config system for creating server endpoints with a unified build process. Adding a
+api.jsextension to a route will ensure it’s only rendered on the server. API routes are hosted from the same dev server as the website and app in development and must be deployed to a dynamic hosting service in production. Learn more in API Routes. This is a very large feature and will remain experimental even after the v3 stable release.
Press enter or click to view image in full size
- Bundle Splitting: Expo CLI now supports bundle splitting on async imports when bundling for web platform. We’ve added this to Expo Router to automatically split on routes and eagerly load chunks to prevent network waterfalls. This also works with static rendering (SSG). Learn more in Async Routes. This was the last major blocker for adding universal React Server Components to Expo.
- Configurable app directory: While not recommended, you can now change the
/appdirectory to be any directory in your project. Learn more about the root directory.
Press enter or click to view image in full size
- Testing Library: To provide robust test coverage for Expo Router, we created a set of Jest utilities that could quickly emulate entire navigation structures. This testing library is now available for public consumption. Learn more in Testing Expo Router.
- URL Support: We’ve added built-in support for the standard URL API and updated all of our APIs to use this, leading to a net bundle size reduction on all platforms, especially web. This is part of a larger effort to improve data fetching across Expo. Learn more about the URL API.
- Not Found routes: To account for API Routes, we’ve added an official convention to match all 404 / Not Found routes. By creating a
+not-found.jsroute, you can match anything that’s unmatched in a directory. This is supported on all native platforms and web in server-mode. When this route is matched, a 404 status code will also be returned on web. Learn more about +not-found. - New
router.navigateAPI: To fix issues with pushing, we’ve changed therouter.pushAPI to always push new routes, whereas the previous version would pop occasionally. You can use the newrouter.navigateAPI to obtain this previous behavior. `Link` components currently use the navigate behavior by default still, but you can change this to use push by passing the newpushprop. e.g.<Link push href=”/” /> - Dynamic Routes on web: The new
serveroutput mode supports server navigation to dynamic routes on web. Previously, you could only perform client-side navigation to routes likeapp/[id].tsxbut the server API is capable of redirecting requests to any route in your project automatically. This is not supported with standard static output. - New Link Props: The Link component now supports
target,rel, anddownloadprops on web. Link also now hasclassNamesupport which works as-is on web and can be used with tools like Nativewind to add Tailwind support on all platforms. - Universal Fast Refresh: We’ve fixed universal Fast Refresh upstream so you no longer need resolutions on react-refresh. The same Fast Refresh implementation now works across all platforms universally and should be substantially more stable!
- Base URL Support: Expo Router now support deploying to subdomains with
experiments.baseUrl— this applies to all platforms so you may want to configure it with an environment variable inapp.config.js. With the addition of this feature, you can now deploy static Expo Router websites to GitHub Pages. We plan to stabilize this API in SDK 51. - Auto Font Optimization: Fonts loaded with
expo-fontare now automatically extracted and preloaded on web when usingstaticorserveroutput. This enables fonts to start loading before the JavaScript has finished, leading to better initial styles. This also enables you to statically render your app even if there’s a top-level render guard. Learn more.
Press enter or click to view image in full size
- Improved Tailwind/PostCSS on web: PostCSS with Expo’s Metro web will no longer be blocked on caching. This means you can use full Tailwind + PostCSS on web and integrate with fantastic UI packages like Shadcn UI (web-only). Metro CSS is now enabled by default!
- Support for external links: You can now link to popular external URLs like
mailto:andsms:which don’t follow the standard://convention of other URLs. - Added mjs and cjs support. All modules are converted to commonjs in the bundler as ESM is not supported on native, but you can now import mjs modules as expected.
- Custom Metro resolvers and transforms: Users can now extend the Metro resolver and modify the transformer using the Babel caller, enabling better control over the bundling process. Learn more in the new Expo Metro docs.
- Improved Typed Routes: Typed routes ensure better stability over time by automatically generating TypeScript types for your project. You can now generate types in CI with
npx expo customize tsconfig.json - tsconfig paths enabled by default: tsconfig/jsconfig path aliases are now enabled by default and follow the TypeScript resolution more closely, they’re also now supported in
jest-expo. - Better Source Maps: Source map exports in production web are now supported, we’ve renamed the
npx expo exportflag--dump-sourcemapto--source-maps— Hermes source maps now work more reliably. - Improved monorepo support: Projects no longer need
expo-yarn-workspacesto enable monorepo support in their app. The majority of standard monorepo functionality is built-in to Expo CLI and Expo Metro Config.
Breaking Changes
- Expo Webpack is deprecated in favor of our universal Metro for web.
- Expo Router v3 only works with Expo SDK 50. Ensure you upgrade your project before upgrading Expo Router.
- The deprecated
useSearchParamsanduseLinkhooks have been removed. - Default CSS reset has been updated to match the latest
[email protected]recommendation. You may need to update your local template or+htmlstyles if you were depending on styles from the previous reset. - React Native Gesture Handler is no longer added automatically. If you use the Drawer navigator or any React Native Gesture Handler features, you’ll need to add the global provider to the Root Layout. We recommend avoiding this dependency on web platforms as it will increase bundle size substantially and mostly be unused on web.
- The
SplashScreenexport is now deprecated, and all the features have been moved upstream toexpo-splash-screen - Remove
expo-router/babelbabel plugin in favor ofbabel-preset-expo - If you have a root
[...missing].tsxroute, rename this to+not-found.tsxotherwise API routes will not be available. Normal routes, including catch-alls, have higher priority over API routes and not found routes. - Expo Router no longer has client-side mocks for
__dirnameand__filenameglobals. - Remove deprecated
<Screen />propredirectin favor of the<Redirect />component which works more reliably. We still plan to improve redirection in the upcoming versions. expo-headnative module is now part of expo-router and should not be installed separately.- The source for expo-router now lives in
buildinstead ofsrc— if you were dangerously importing nested modules, update them to useexpo-router/build/*
Bug Fixes
We’ve been actively fixing bugs and improving stability with Expo Router. The majority of notable fixes have all been backported to v2 and released progressively throughout the previous release-cycle.
Get Evan Bacon’s stories in your inbox
Join Medium for free to get updates from this writer.
Remember me for faster sign in
Expect improved TypeScript support, more stable redirection, smaller bundle sizes, and better web support.
Using the Beta
- Initialize a new project with SDK 50 beta:
npm:npx create-expo-app --template tabs@betayarn:yarn create expo-app --template tabs@betaNote:create-expo-appwill install dependencies with npm whennpxis used and yarn whenyarn createused. - Upgrade an existing project:
Install the beta version of the Expo package:npm install expo@nextoryarn add expo@next
Upgrade all dependencies to match SDK 50:npx expo install --fix - Install the latest Expo Go for iOS to your physical device:
Use this TestFlight open beta link and follow the instructions. - Install the latest Expo Go for iOS simulators or Android emulators/physical devices:
Launch your project through Expo CLI (press theiorakeyboard shortcut after runningnpx expo start) and the updated version of Expo Go will be automatically installed. - SDK 50 beta is not yet available on Snack.
- Read the documentation by selecting it from the version selector in the API reference section.
Migrating from Expo Router v2 to v3
- Ensure you remove any Yarn
resolutionor NPMoverridesespecially formetro,metro-resolver, andreact-refresh. If you skip this, then Fast Refresh may not work as expected. - Possibly the largest behavior change in any version of Expo Router––
router.pushis nowrouter.navigateandrouter.pushalways pushes routes. This is technically a bug fix, but it may cause unexpected changes in complex navigation behavior. - Remove the
expo-router/babelpreset in favor ofbabel-preset-expoand be sure to clear the Metro cache before restarting your dev server—this means runningnpx expo start --clearornpx expo export --clear - If you have a top-level
[...missing].jsroute, ensure you rename this to+not-found.jsif you plan to use API Routes. Otherwise, you’ll only see the “not found” route when you ping an API endpoint. react-native-gesture-handleris no longer added automatically and must be injected if you wish to use the drawer navigator. We recommend avoiding this dependency on web platforms as it will increase bundle size substantially and mostly be unused on web. Learn more Drawer navigator.- Enable Async Routes on web to use the new bundle splitting functionality on web. Async Routes may have issues on Android with Reanimated, you can disable the feature per-platform if needed.
- If you have custom splash screen handling, change the import of
SplashScreeninexpo-routertoexpo-splash-screen - If you were using the
hrefAttrsprop on theLinkcomponent for adding additional web props, migrate to top-level props by the same name, e.g.hrefAttrs={{ target: '_blank' }}should now betarget="_blank"— this applies totarget, rel, download— all of which are web-only and automatically shimmed on native. - If you’re using the
react-native-webstyle escape hatch (style={{ $$css: true, _: “myclass” }}) to setclassNameon Link components for web, migrate to the top-levelclassNameprop, e.g.<Link className="myclass" />
How to report issues
- Create an issue on https://github.com/expo/expo/issues and be sure to fill out the appropriate template (and include a minimal reproducible example, please!).
- Figuring out the underlying causes of issues is super helpful.
- Let us know that you are using the SDK 50 beta so we can prioritize the issue.
- The most helpful beta testers will be listed in the final release notes (and possibly even provided with some Discord flair — you can link your Discord and GitHub accounts to your Expo account).
- Do not report issues to expo/router as this repo will now be archived.
Thank you for helping us with testing the release — we look forward to shipping it soon! 🚀
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.