Skip to content
Back to journal
Next.jsWeb to AppAndroid

Convert a Next.js App to a Mobile App Without Losing SSR (2026)

CCode2Native EngineeringEngineering team
2026-07-24

There are two honest readings of “convert Next.js to a mobile app.” One is a rewrite: port the UI to React Native or Flutter and maintain two codebases forever. The other starts from what a Next.js app already is: a server, deployed and running, that any Chromium-based browser can render. An Android WebView is one of those browsers.

This post is about the second reading. Code2Native takes your production URL — on Vercel or self-hosted, it doesn't matter — and wraps it in a native Android shell: your icon, your splash screen, OneSignal push, compiled and signed into an APK/AAB in a few minutes. To be precise about what that is: a native shell rendering your live deployment, not a native rewrite. Your server components stay on your server. Your app store listing points at your CI/CD pipeline.

The rest of this guide is the Next.js-specific detail: what your middleware does to an unfamiliar client, how ISR timing shows up on installed phones, and the one genuine trap — third-party OAuth — that catches Next.js apps more than any other stack.

Why you wrap the URL, not the repo

A plain React SPA is a folder of static files — you can physically copy it into a Capacitor shell and ship it on the device. We cover that route in the React version of this guide. A Next.js app is not that. It's a running system: server components render on the server, middleware sits at the network boundary, ISR regenerates pages on the host, API routes and server actions execute next to your database.

The one official way to freeze Next.js into static files — output: "export" — disables exactly the features you chose Next.js for: no SSR, no middleware, no ISR, no API routes, and next/image needs a custom loader. That's why the Capacitor-with-static-export route, which works fine for Vite SPAs, is usually a downgrade for Next.js apps (our Capacitor vs native comparison is the longer discussion). Wrapping the deployed URL keeps the whole stack intact because the phone is just another client of your deployment.

Mechanically, our pipeline generates a real Android project around a Chromium WebView pointed at your URL, layers in the native pieces — icon, splash, package ID, OneSignal push — and compiles and signs an APK and a Play-ready AAB in the cloud with a per-project keystore, typically in a few minutes. That's the whole trick; the full technical rundown lives in the docs.

What survives the wrap: a Next.js feature audit

Evaluate the wrapper like any new client of your API — feature by feature:

Next.js featureIn the wrapped appWhy
SSR & Server ComponentsWorks unchangedRendering happens on your server; the app is just another client
App Router / Pages Router navigationWorks unchangednext/link pushes History API entries; the Android back button steps through them
Middleware / proxy.tsWorks — audit itRuns server-side on every request the app makes; see the preflight below
ISR & cachingWorks unchangedUpdates reach installed phones on your revalidate schedule, no store review
next/imageWorks — check config/_next/image is same-origin; remote hosts must be in remotePatterns
API routes & server actionsWorks unchangedSame-origin fetches with cookies, exactly as in mobile Chrome
Third-party OAuth (Google, GitHub)Needs real careGoogle blocks its OAuth endpoint inside embedded WebViews — full section below
Offline modeNot a wrapper featureThe app renders your deployment; no connection, no app

Four deployment checks before you spend the free build

1. Wrap the production domain — never a *.vercel.app preview URL

As of mid-2026, new Vercel projects ship with Deployment Protection enabled, which puts Vercel Authentication in front of preview URLs by default. Wrap a preview URL and your shiny new app opens to a Vercel login wall. Production domains stay public, so point the wrapper at https://yourapp.com. And if your app is served under a basePath (say /app), give the wrapper the full URL including that path — internal next/link navigation already stays under it, so nothing else changes.

2. Audit your middleware — or proxy.ts, post-Next 16

Since Next.js 16, middleware.ts is deprecated in favor of proxy.ts (there's a codemod: npx @next/codemod@latest middleware-to-proxy .). Whatever yours is called, it runs on every request the app makes — read it once with a WebView client in mind. The usual suspects: geo or locale redirects that bounce users to a country subpath on first load, auth guards that redirect to /login and back, and user-agent sniffing that lumps unfamiliar UA strings in with bots. A redirect chain a desktop browser shrugs off is very visible as the first thing your app does after the splash.

3. Check remotePatterns if you load remote images

next/image works fine in the app — the optimizer endpoint is same-origin, so there's nothing WebView-specific about it. The failure mode is the one you know from the browser: a remote host missing from your config returns a 400 and a broken image — identically broken in the app. If your content images come from a CMS or object storage, make sure the allowlist covers them:

// next.config.ts
images: {
  remotePatterns: [
    { protocol: "https", hostname: "images.ctfassets.net" },
    { protocol: "https", hostname: "*.supabase.co" },
  ],
},

Fix it once at the source and both web and app are fixed.

4. Know your ISR windows

When a route uses revalidate, Next.js emits s-maxage plus stale-while-revalidate directives that Vercel's CDN consumes, serving cached HTML until the window expires. For the app this is mostly good news: content updates reach installed phones with zero rebuilds and zero store reviews — but on ISR's schedule, not the instant you hit merge. If a stakeholder expects the app to be “live” the second a CMS entry changes, check the route's actual revalidate window or wire up on-demand revalidation before they file it as an app bug.

The real trap: OAuth pops out of the WebView

Google's “Use secure browsers” policy has hard-blocked its OAuth authorization endpoint inside embedded WebViews for years — users see 403: disallowed_useragent instead of an account picker. This applies to every WebView wrapper on the market; any vendor implying otherwise is describing a policy violation. So “Sign in with Google” must leave the shell and complete in the system browser or a custom tab.

The subtle part is what happens after: the session that OAuth flow creates lives in the external browser's cookie jar. The app's WebView has its own. Without deliberate handling, the user “logs in,” switches back to your app, and is still anonymous — the single most confusing failure mode a wrapped app can ship with.

What actually works

Keep one first-party login path alive: Auth.js/NextAuth credentials, or an email one-time code the user types inside the app. Cookies set by your own domain behave normally in the WebView, so first-party sessions persist exactly like in a browser. Avoid magic links as the only option — tapping one in Gmail opens the phone's default browser and creates the session there, same trap. If OAuth is currently your only door, test your login end to end on the free first build before you publish anything.

Android today, iOS honestly, Windows if you're on Agency

Android is the fast path: a signed APK for direct testing and an AAB for Google Play, built with a per-project keystore, in a few minutes. You'll need an app icon of at least 512×512 (PNG) and, for the store, Google's $25 one-time developer account. Push via OneSignal is wired into the shell — for a SaaS or content product it's the one genuinely native capability that justifies the app over a bookmark. The generic walkthrough of the free build and Play submission is in our free-Android-build guide.

iOS deserves plain language, because this is where web-to-app marketing tends to lie. All of our cloud iOS .ipa builds — signed or unsigned — require the Pro plan or higher and run on real Apple silicon. The default output is an unsigned .ipa that you re-sign with your own Apple Developer certificate ($99/year to Apple). On Pro and above you can instead upload your own .p12 certificate to an encrypted vault and get a cloud-signed .ipa back. Either way, we never ask for your Apple ID or App Store Connect access, and App Store submission stays yours — we don't file it for you. The zero-signing route is the iOS Web Clip: a tap-to-install home-screen icon with no certificate involved. And the structural caveat: Apple's guideline 4.2 rejects apps that are “essentially a repackaged website,” so a wrapped marketing site has poor App Store odds — a real logged-in SaaS does considerably better.

Windows is a different product surface entirely: on the Agency tier we also wrap the same deployed Next.js URL into a Windows EXE. That path has its own guide — converting Next.js to a Windows EXE — and shares nothing with the mobile pipeline except the URL you paste.

If what you have is source code, not a URL

Next.js shops usually have other codebases too. Code2Native's other product surface compiles uploaded source — Flutter, native Android (Gradle), and Capacitor projects that include an android folder — into signed binaries with era-matched toolchains. React Native, Ionic, and Expo source builds are currently waitlist-only, not live. Next.js itself isn't a source-build target — its whole value is server-side, which is exactly why the wrapper path above is the Next.js path.

What it costs

Your first Android build is free — one build credit, watermarked splash — so test the wrap on a real device before paying anything. After that it's credit-based: Starter at $29/month for 10 credits ($290/year), Pro at $99/month for 30 credits and cloud iOS builds ($990/year), Agency at $199/month for 100 credits plus Windows EXE and white-label branding ($1,690/year). A failed build refunds its credit automatically, $49 buys an urgent priority build, and payment is by card (Stripe) or USDT. The current numbers always live on the pricing page.

FAQ

Can I convert a Next.js app to a mobile app without rewriting it?

Yes, if a wrapper fits your product. Your deployed Next.js app is a running server that any Chromium browser can render, and an Android WebView is one of those browsers. We wrap your production URL in a native shell and return a signed APK/AAB in minutes, with OneSignal push. It's your live site in a shell — not a native rewrite — so server components, middleware, ISR, and API routes keep running on your server. If you need offline mode or heavy native UI, that's rewrite territory — a different project entirely.

Does SSR and the App Router work inside the wrapped app?

Yes. The Android WebView is Chromium-based, so server-rendered HTML, React Server Components, streaming, and client-side transitions via next/link behave as they do in mobile Chrome. Both routers push real History API entries, so the Android back button steps backward through in-app navigation instead of closing the app. Middleware (proxy.ts in Next.js 16), ISR, and API routes are untouched — they run on your server, not the device.

Why does Google sign-in fail inside a WebView app?

Google's “Use secure browsers” OAuth policy blocks its authorization endpoint in embedded WebViews — users get a 403 disallowed_useragent error. The flow has to hop to the system browser, and a session created out there doesn't automatically exist in the app's WebView. The reliable fix is one first-party login path — credentials or an email code typed inside the app — since your own domain's cookies work normally in the WebView. If OAuth is your only login, test the free first build before publishing.

Do I get an iOS app too?

Cloud iOS .ipa builds run on real Apple silicon and require Pro or higher — every cloud iOS build, signed or unsigned. The default is an unsigned .ipa you re-sign with your own Apple Developer certificate ($99/year to Apple); on Pro and above you can instead upload your own .p12 to an encrypted vault and get a cloud-signed .ipa back. We never ask for your Apple ID or App Store Connect access, and App Store submission is yours — we don't file it for you. The zero-signing route is the iOS Web Clip, a home-screen install with no certificate at all.

Does the app update when I redeploy on Vercel?

Yes. The app renders your live deployment, so every production deploy reaches installed phones with no rebuild and no store review. The one nuance is ISR: statically regenerated pages update on your revalidate schedule, not instantly. You rebuild the app only when the native shell changes — icon, app name, package ID, or push configuration.

What does this cost for a Next.js app?

The first Android build is free — one credit, watermarked splash — so you can test on a real device before paying. Then it's credit-based: Starter $29/month for 10 credits ($290/year), Pro $99/month for 30 plus cloud iOS builds ($990/year), Agency $199/month for 100 plus Windows EXE and white-label ($1,690/year). Failed builds auto-refund their credit, $49 buys an urgent build, and we accept Stripe or USDT. Google Play's developer account is a separate $25 one-time fee.

Point the wrapper at your deployment and judge it on a real phone

The first Android build is free: paste your production URL, and in a few minutes you'll have a signed APK on a device — server components, middleware, ISR and all. Test your login flow while you're at it; the build will tell you more than this post can.

C

Code2Native Engineering

Engineering team

Written by the Code2Native engineering team — the people who build and operate the cloud build pipeline.