K
Kinde2w ago
Tito

Vercel Edge Nodes and expoSecureStore in NextJS SDK

I updated Vercel to Node 22 and now I can't deploy anymore. It seems that the NextJS Kinde SDK includes some Expo (react native?!) modules that are not supported.
Error: The Edge Function "src/middleware" is referencing unsupported modules:
- __vc__ns__/0/index.js: ./expoSecureStore-DT0Gf-SP.js, ./expoSecureStore-C1h3JFYV.js
Error: The Edge Function "src/middleware" is referencing unsupported modules:
- __vc__ns__/0/index.js: ./expoSecureStore-DT0Gf-SP.js, ./expoSecureStore-C1h3JFYV.js
Setting runtime = 'nodejs' in middleware.ts did not solve it.
8 Replies
Tito
TitoOP2w ago
Claude suggests to rewrite middleware.ts to avoid importing withAuth to:
import { NextRequest, NextResponse } from "next/server";

export default function middleware(req: NextRequest) {
// Get the access token from cookies
const accessToken = req.cookies.get('kinde-access-token');
const refreshToken = req.cookies.get('kinde-refresh-token');

// Check if user is authenticated
const isAuthenticated = accessToken || refreshToken;

// If not authenticated, redirect to login
if (!isAuthenticated) {
const loginUrl = new URL('/api/auth/login', req.url);
loginUrl.searchParams.set('post_login_redirect_url', req.url);
return NextResponse.redirect(loginUrl);
}

// Continue to the requested page
return NextResponse.next();
}

export const config = {
matcher: ["/dashboard/:path*", "/admin/:path*", "/dashboard", "/admin"],
};
import { NextRequest, NextResponse } from "next/server";

export default function middleware(req: NextRequest) {
// Get the access token from cookies
const accessToken = req.cookies.get('kinde-access-token');
const refreshToken = req.cookies.get('kinde-refresh-token');

// Check if user is authenticated
const isAuthenticated = accessToken || refreshToken;

// If not authenticated, redirect to login
if (!isAuthenticated) {
const loginUrl = new URL('/api/auth/login', req.url);
loginUrl.searchParams.set('post_login_redirect_url', req.url);
return NextResponse.redirect(loginUrl);
}

// Continue to the requested page
return NextResponse.next();
}

export const config = {
matcher: ["/dashboard/:path*", "/admin/:path*", "/dashboard", "/admin"],
};
I don't know if those cookie names are accurate or hallucinated. This seems to trigger a redirection infinite loop.
Abdelrahman Zaki - Kinde
Hey @Tito, could you please let me know which version of @kinde-oss/kinde-auth-nextjs you’re using?
Tito
TitoOP2w ago
"@kinde-oss/kinde-auth-nextjs": "^2.8.6", i tried to upgrade to the latest, is it the latest? I haven't set any route or page to edge, so it looks like it's an issue with the vercel deploy process. I can build correctly, but it fails when running it. It seems that some Expo related dependency ended up in the kinde-auth-nextjs package by mistake? I am not sure what triggered the problem for me, most likely I clicked on the "upgrade" request (from node 18 to node 20) on vercel The problem is with @kinde/js-utils that dynamically imports expo-local-storage This is the dependency tree:
Your package.json
└── @kinde-oss/kinde-auth-nextjs@2.8.6 (direct dependency)
├── @kinde-oss/kinde-typescript-sdk@2.12.0
│ └── @kinde/js-utils@0.19.0 (transitive)
└── @kinde/js-utils@0.21.2 (transitive)
Your package.json
└── @kinde-oss/kinde-auth-nextjs@2.8.6 (direct dependency)
├── @kinde-oss/kinde-typescript-sdk@2.12.0
│ └── @kinde/js-utils@0.19.0 (transitive)
└── @kinde/js-utils@0.21.2 (transitive)
This is a total blocker, I am stuck. js-utils is cross platform, but Vercel can't deploy it I've tried a number of tricks in next.config.js to avoid bundling the expo-local-storage package, but nothing worked. This is my config file:
const createNextIntlPlugin = require('next-intl/plugin');

const withNextIntl = createNextIntlPlugin();

/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
domains: ['upcdn.io'],
},
experimental: {
serverComponentsExternalPackages: [
'@kinde-oss/kinde-auth-nextjs',
'@kinde/js-utils',
'@kinde-oss/kinde-typescript-sdk'
],
},
webpack: (config, { isServer, isEdge }) => {
const path = require('path');

// Replace expo-secure-store with our stub
config.resolve.alias = {
...config.resolve.alias,
'expo-secure-store': path.resolve(__dirname, 'lib/expo-secure-store-stub.js'),
};

// Add a plugin to ignore expo modules during bundling
config.plugins = config.plugins || [];
config.plugins.push({
apply(compiler) {
compiler.hooks.normalModuleFactory.tap('ExpoModuleIgnorePlugin', (factory) => {
factory.hooks.beforeResolve.tap('ExpoModuleIgnorePlugin', (data) => {
if (data && data.request && data.request.includes('expoSecureStore')) {
return false;
}
});
});
},
});

return config;
},
};

module.exports = withNextIntl(nextConfig);
const createNextIntlPlugin = require('next-intl/plugin');

const withNextIntl = createNextIntlPlugin();

/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
domains: ['upcdn.io'],
},
experimental: {
serverComponentsExternalPackages: [
'@kinde-oss/kinde-auth-nextjs',
'@kinde/js-utils',
'@kinde-oss/kinde-typescript-sdk'
],
},
webpack: (config, { isServer, isEdge }) => {
const path = require('path');

// Replace expo-secure-store with our stub
config.resolve.alias = {
...config.resolve.alias,
'expo-secure-store': path.resolve(__dirname, 'lib/expo-secure-store-stub.js'),
};

// Add a plugin to ignore expo modules during bundling
config.plugins = config.plugins || [];
config.plugins.push({
apply(compiler) {
compiler.hooks.normalModuleFactory.tap('ExpoModuleIgnorePlugin', (factory) => {
factory.hooks.beforeResolve.tap('ExpoModuleIgnorePlugin', (data) => {
if (data && data.request && data.request.includes('expoSecureStore')) {
return false;
}
});
});
},
});

return config;
},
};

module.exports = withNextIntl(nextConfig);
i don't understand why i didn't have the problem, i always used next 14 in this project. The only thing that happened is upgrading to node 20 and 22. I was on @kinde-oss/kinde-auth-nextjs 2.3.10 until today; when i encountered the issue I upgraded to the latest version 2.8.6 today, but that didn't solve it.
Abdelrahman Zaki - Kinde
Hey @Tito, thank you for all the detailed notes and the dependency tree, that’s really helpful. I’ll investigate this first thing tomorrow. I really appreciate your patience here. Please feel free to share anything else you discover in the meantime - I’ll make sure to pick it up when I start.
Tito
TitoOP2w ago
By default middleware is always run on edge runtime. It's only recently in some Next 15.x version that they added an experimental flag to run middleware on nodejs runtime (which probably would bypass the issue; i have not tried). Maybe Node18 didn't check and given that expo is not actually used, it never triggered any error
Abdelrahman Zaki - Kinde
Hey @Tito, I’ve just finished attempting to replicate the issue using Next 14, the same library versions you listed, with Node 22, and deployed it to Vercel. The deployment completed successfully without triggering the unsupported modules error. You can review the reproduction here: - GitHub repo: https://github.com/abdelrahman-zaki/kinde-nextjs-edge-repro - Deployed Vercel URL: https://kinde-nextjs-edge-repro.vercel.app/ This should help as a baseline to compare against your project’s setup so we can pinpoint any differences that might be causing the failure on your side.
GitHub
GitHub - abdelrahman-zaki/kinde-nextjs-edge-repro
Contribute to abdelrahman-zaki/kinde-nextjs-edge-repro development by creating an account on GitHub.
Kinde Auth
Kinde with NextJS App Router
Tito
TitoOP2w ago
Thanks. I believe the fix was to upgrade Next from 14.1.x to 14.2.31 as the older version conflicted with Node 20
Abdelrahman Zaki - Kinde
Got it, thanks for confirming. Good to hear upgrading to Next 14.2.31 fixed the issue. Let me know if you run into any other issues.

Did you find this page helpful?