I am creating a full stack application with next js 13, I have created an API that is perfectly working in dev(npm run dev) mode but the problem is when I give the build command(npm run build) then it shows the flowing error. Please anybody bring me out of the problem. Error Screenshot - https://prnt.sc/VaN1wHifqK_2
[Error]: Dynamic server usage: Page couldn't be rendered statically because it used `nextUrl.searchParams`. See more info here: https://nextjs.org/docs/messages/dynamic-server-error
Here is my code. This is the API function for getting users from the database using url searchParams
// /backend/apiControllers/getUsers.js
import prisma from "@/prisma/prismaClient";
export const getUsers = async (request) => {
const { nextUrl } = request; // here is the problem, this is working for dev mode but not in production build mode.
const email = nextUrl.searchParams.get("email") || "";
const phone = nextUrl.searchParams.get("phone") || "";
const id = nextUrl.searchParams.get("id") || "";
let queryParam = {};
if (email) {
queryParam = {
where: {
...queryParam.where,
email: {
equals: email,
mode: "insensitive",
},
},
};
}
if (phone) {
queryParam = {
where: {
...queryParam.where,
phone: {
equals: phone,
},
},
};
}
if (id) {
queryParam = {
where: {
...queryParam.where,
id: {
equals: id,
},
},
};
}
try {
const users = await prisma.users.findMany(queryParam);
return users;
} catch (error) {
return { apiMessage: { errorMsg: "Unable to find User details" } };
}
};
And I have called that function into /app/api/armies/route.js
// /app/api/armies/route.js
import { getUsers } from "@/backend/apiControllers/getUsers";
import { connectDB } from "@/backend/utils/dbConnect";
import { NextResponse } from "next/server";
export const GET = async (request) => {
try {
await connectDB();
const users = await getUsers(request); //called here
return NextResponse.json(users);
} catch (error) {
console.log(error);
return NextResponse.json({
apiMessage: { errorMsg: "Internal Server Error, Please try again later" },
});
}
};
I have tried the following method also "const url = new URL(request.url);" but the same error, Here is the error screenshot - https://prnt.sc/Z3D317lDQ3CP
import prisma from "@/prisma/prismaClient";
export const getUsers = async (request) => {
const url = new URL(request.url); // here is the problem, this is working for dev mode but not in production build mode.
const email = url.searchParams.get("email") || "";
const phone = url.searchParams.get("phone") || "";
const id = url.searchParams.get("id") || "";
let queryParam = {};
if (email) {
queryParam = {
where: {
...queryParam.where,
email: {
equals: email,
mode: "insensitive",
},
},
};
}
if (phone) {
queryParam = {
where: {
...queryParam.where,
phone: {
equals: phone,
},
},
};
}
if (id) {
queryParam = {
where: {
...queryParam.where,
id: {
equals: id,
},
},
};
}
try {
const users = await prisma.users.findMany(queryParam);
return users;
} catch (error) {
return { apiMessage: { errorMsg: "Unable to find User details" } };
}
};
But again the same error
In Next.js, Every page and route handler(1) are static by default then Next.js will (bail out) opt out to dynamic rendering when using Runtime data such as searchParams
or headers
. The way Next.js knows when dynamic data is used is by throwing custom errors and catch them to switch the renderer method. Simply, when you use the request URL (e.g. request.nextUrl
) Next.js internally will throw DynamicServerError
and catch it at a top-level.
While generating static pages, Next.js will throw a DynamicServerError if it detects usage of a dynamic function, and catch it to automatically opt the page into dynamic rendering. However, when it's uncaught, it will result in this build-time error.
Let's look at this snippet from your code:
try {
const users = await getUsers(request); //called here
// At the previous line, We used `request.url` / `request.nextUrl`
// Next.js has thrown a `DynamicServerError`
return NextResponse.json(users);
} catch (error) {
// Wait!
// We are trying/catching errors here, so any thrown error withen
// the try block will no longer be thrown. As a result,
// Next.js no longer knows when you use dynamic data
return NextResponse.json({
apiMessage: { errorMsg: "Internal Server Error, Please try again later" },
});
}
Note: Read the comments in the code block if you haven't
Did you get it?
We have two solutions:
try/catch
statmentsconst searchParams = request.nextUrl.searchParams
try {
const users = await getUsers({ searchParams });
return NextResponse.json(users);
// ...
This way, Next.js will throw its errors and catch them without a stumbling block.
You can also, catch all errors then re-throw Next.js-specific errors to handle them. Next.js provides some utilities to know the error.
import { isDynamicServerError } from "next/dist/client/components/hooks-server-context";
// ...
try {
const {nextUrl} = request;
} catch (error) {
if (isDynamicServerError(error)) {
throw error;
}
// handle other errors
}
When using some of Next.js functions inside try
you need to re-throw them. for example, isNotFoundError
for notFound()
, isRedirectError
for redirect
.
import { isStaticGenBailoutError } from "next/dist/client/components/static-generation-bailout";
import { isNotFoundError } from "next/dist/client/components/not-found";
import { isRedirectError } from "next/dist/client/components/redirect";
import { isDynamicServerError } from "next/dist/client/components/hooks-server-context";
There is a proposal to introduce a new API rethrow
that you can call it in the catch
block to rethrow all next.js errors.
unstable_rethrow
is out as of [email protected]
, you can call it in the catch
block to rethrow Next.js specific errors:
try {
redirect("/");
notFound();
request.nextUrl.searchParams;
// ...
await getData();
} catch (error) {
unstable_rethrow(error)
// handle your errors
console.error(error)
}
(1) Starting from next@15
, Route Handlers are dynamic by default.