Next.js Discord

Discord Forum

What's the best way to handle prod builds?

Unanswered
Mini Rex posted this in #help-forum
Open in Discord
Mini RexOP
Hey guys so in my current setup I do the following:

build the docker image locally (using --experimental-build-mode compile while building the app since I don't have access to my prods db locally)
upload the image to my registry and then pull it automatically from the server
automatically start the container on the server

outcome:
everything works, but I'm not seeing the x-nextjs-cache header.

so I guess that complementing --experimental-build-mode compile with --experimental-build-mode generate is required, but wouldn't that require to have node modules in the image 😭

Would spinning up a dummy DB locally and then using the regular build with no experimental flag be sufficient? I guess I would need to revalidate everything on payload init otherwise there would be blank pages?

35 Replies

you can create a standalone build
which is way small in size and I don't think it has all the node modules but only the one your app needs
https://github.com/PhantomKnight287/saturn/ the above ss is of docker image of the attached repo. mentioning for a comparison of repo size to image
Mini RexOP
yep I'm using that, but I needed to find a way to generate the html the pages on server start because I don't have access to prod db locally
found out a way though
@Mini Rex found out a way though
Saint Hubert Jura Hound
Using generatestaticparams?
Mini RexOP
yes in combination with --experimental-build-mode generate
had to sacrifice a bit on the image size
@Mini Rex had to sacrifice a bit on the image size
Saint Hubert Jura Hound
I dont think that flag is still required then
Mini RexOP
it is, pages get dynamic rendered then
try locally
and no caching
so my flow is: do the heavy lifting locally by compiling the site and then generating everything on the server which has access to the db and latest data
@Mini Rex it is, pages get dynamic rendered then
Saint Hubert Jura Hound
They should still get dynamically generated without the flag.. thats what generatestaticparams does for unknown route params by default which is what happens for example when during build u didnt have access to params data
Mini RexOP
no io meant they get dynamically generated if u just compile without generating
@Mini Rex no io meant they get dynamically generated if u just compile without generating
Saint Hubert Jura Hound
Oh i see. Sure but its still gonna get cached. Only on the first request does nextjs need to generate, after it only revalidates after the configured time
Mini RexOP
yeah but I was missing out completely on caching, there were no x-nextjs-cache headers appended to the html responses (unless there is something I'm not aware of - just got into nextjs yesterday)
my build output looks like this now on the server:
@Mini Rex yeah but I was missing out completely on caching, there were no x-nextjs-cache headers appended to the html responses (unless there is something I'm not aware of - just got into nextjs yesterday)
Saint Hubert Jura Hound
Afaik the reason youd switch to generating at runtime is when u have very large amounts of pages so as not to bloat ur docker img. Otherwise its best to generate during build to prevnt extra server load.
So ig what im suggesting is get a mock db in ci so u can use generatestaticparams properly.

Besides that the fact that no cache headers were available doesnt seem normal in this case. If u were already using generatsstaticparams..
Idk how that would be possible
Mini RexOP
wait so are u saying that i can simply start a mock db locally, just use the regular build without these experimental flags
Saint Hubert Jura Hound
I personally have a route that doesnt have param data available during build and generatestaticparams cache works fine for me
@Mini Rex wait so are u saying that i can simply start a mock db locally, just use the regular build without these experimental flags
Saint Hubert Jura Hound
Well even without the mock db u could lose the experimental flag afaik
I dont use it myself
But the mock db is the best solution either way
Mini RexOP
the regular build is breaking bc it tries to populate the pages with api data
Saint Hubert Jura Hound
Unless ur generating 1000's or 10000's of pages
@Mini Rex the regular build is breaking bc it tries to populate the pages with api data
Saint Hubert Jura Hound
Yea there was a splution to this but it depeds on whether or not ur using cache components
Without cache components u can just return an empty array and i think u might have to export some nextjs constant. Lemme check my own code in a few mins tho
Cuz i use cache components, bit diff there
Mini RexOP
i will try the mock db approach
Saint Hubert Jura Hound
Ah yep, so for cache components the workaround is to insert this placeholder value
export async function generateStaticParams() {
  try {
    const client = await getServerApiClient(PlanService, false)
    const gameToPlans: Record<string, Plan[]> = {}

    // TODO: create plans for more games
    await Promise.all(
      (["Minecraft", "Rust"] as GameIdentifier[]).map(async (identifier) => {
        const plansResult = await getPlansForGame(client, identifier)
        if (!plansResult.ok) {
          reportError(
            "Error getting /plans/[game]/[planId] page data",
            plansResult.error
          )
          return
        }
        gameToPlans[identifier] = plansResult.data
      })
    )

    const params = Object.entries(gameToPlans).flatMap(([identifier, plans]) =>
      plans.map((plan) => ({
        game: GAMES[identifier as GameIdentifier].slug,
        planId: plan.planId,
      }))
    )

    return params.length > 0
      ? params
      : [{ game: "__placeholder__", planId: "__placeholder__" }]
  } catch {
    return [{ game: "__placeholder__", planId: "__placeholder__" }]
  }
}

export default async function page(props: PageProps<"/plans/[game]/[planId]">) {
  "use cache"
  const { game: slug, planId } = await props.params

  if (slug === "__placeholder__" || planId === "__placeholder__") {
    notFound()
  }
@Mini Rex i will try the mock db approach
Saint Hubert Jura Hound
The placeholder workaround shouldnt be necessary with the mock db, unless ur db returns no values
Then its still useful