Password-reset emails, referral invites, and order confirmations all end the same way: a link that should land on the right screen. In development the link works because the simulator is warm, the session is fresh, and you tap it from the same device. In production it breaks because the app was killed, the session expired, or the user pasted the link into a notes app first.
Deep linking is not one feature. It is three layers that have to agree: the operating system deciding your app owns the URL, the router mapping that URL to a screen, and your app handling whatever state it wakes up in. When AI coding tools scaffold the router for you, the middle layer looks done while the other two are still missing. This post closes that gap for Expo apps built with Expo Router.
Why links fail after the demo
Most production deep-link bugs fall into four buckets. First, the OS never hands the URL to your app because the domain association file is missing or the native config is wrong, so the link opens in the browser instead. Second, the app opens but lands on the home screen because the route path does not match the URL structure. Third, the app lands correctly on a warm start but drops the destination on a cold start, when the JavaScript bundle loads after the OS delivers the intent. Fourth, the destination screen assumes an authenticated user, redirects to login, then forgets where it was going.






