Some pitfalls in deploying a Next JS web application

I have deployed Next JS applications for so many time, and each time there will always be an issue running it as a static site. This blog will go through some problems I have faced and how I dealt with it(sort of).

Working as a DevOps/Cloud Engineer, I have been tasked many times to build a pipeline that deploy a Next JS application to a static hosting site. Most of the time, it goes down like this, the developers run the application totally fine on their local environment. Then, things start to go bad once the source code is shipped to Github and the build pipeline fails. In this post, I will talk about the build issues I have faced so far and how I managed to resolve it.
Please note that I have tried my best to read and explain how things work in Next JS but I don't guarantee what I wrote here is 100% correct and up to date, its best to read the Next JS documentation for more detail.

The first pitfall(type of rendering)

This is easily one of the most important factors that I usually overlook. In fact, this is where the problem is originated from most of the time. Having a clear understanding on this topic would help tremendously in debugging deployment issue.

Server Side Rendering(SSR) and Client Side Rendering(CSR)

These two type of rendering is contradictory to one another. If you understand one, you probably will also get the other one and the name is also pretty much self-explanatory. One same feature for both of them is that what is on your screen when you enter the site might have just been rendered right at that moment. Therefore, these two are suitable for website with contents that is constantly changed. The difference comes from where that generation is done, for SSR, it is done on the server and for CSR on client which is our browser. To declare your component use CSR, add this code to your page
use client
this declaration helps Next JS to use the right API as by default, it will assume all API calls are for server components.

Static Site Generation(SSG)

SSG is different from the aboves in that what you see when you visit the website might is generated at the time the website is built, and you have just been another viewer of that file. The server achieve this by pre-render everything and put into an html. It will only need to serve this to every viewer that visit the site. Based on the description, this is obviously suitable for websites with rarely changed content or of no interaction with users.

Incremental Static Regeneration(ISR)

ISR combine the best of both world with static generation from SSG and the ability to update it once there are new changes which are the trait of SSR and CSR.

My solution on this

Next JS determines which rendering to use based on the usage of specific functions in the code. For example, Pages without any server-side dependencies (no getServerSideProps, getStaticProps, or blocking data fetching using getInitialProps) will automatically be treated as static. Because my website content is non interactive and rarely change, SSG is the most suitable option. To tell Next JS to use SSG, you can just avoid putting the above functionalities inside your page.

The second pitfall (use of routing)

Usually when you work on a website, implementation of dynamic routing might be needed. For instance, my website uses it for routing the blog content pages. To make dynamic routing works on static hosting, you need to define all the possible routes to Next JS when the static build is made. For example, I can tell Next JS all the possible routes to every of my blog post using this code. Next JS will then generate multiple static version for each of my blog post page from the routes I have provided at build time.

export async function generateStaticParams() {
    const posts = getAllPosts(['slug']);

    return posts.map((post) => ({
        slug: post.slug,
        }))
}

Please note that if you still use Pages Router, the function is called getStaticPaths. Without this function, Next JS will gives you an error when you try to export the static build as it doesn't know what to do with the dynamic routing part.

The third pitfall (image rendering)

Image rendering is also another interesting topic that I never notice until I need to deal with the no image exists error. Next JS supports what is called Image Optimization by using its own Image Component. You then specify your local path for the Image Component to process and optimize your image. The problem starts here because Image Component is a server component. This means when the image need to be fetched, clients will query the image to a Next JS API on the server called _next/image for the optimized image. This is a problem because in static hosting, there is no server to process this request. To fix this, you need to set the path directly to the src of the Image Component. Therefore, telling the client to just retrieve the image directly using the provided path rather than trying to query the Next JS API. The first code is the original code that gives 404 when Image is accessed and the second code is the fixed version.

import fargateDemoImg from '../../../public/projects-assets/project_1/architecture-diagram.png';
<--my blog code-->
<a target="_blank" rel="noreferrer" href={projectUrl}>
    <Image
        src={img}
        alt=""
        className="object-cover aspect-video"
    />
</a>
import fargateDemoImg from '../../../public/projects-assets/project_1/architecture-diagram.png';
<--my blog code-->
<a target="_blank" rel="noreferrer" href={projectUrl}>
    <Image
        src={img.src}
        alt=""
        className="object-cover aspect-video"
        width={img.width}
        height={img.height}
    />
</a>

End

Those are the pitfalls I have faced so far trying to deploy a Next JS application on a static hosting site. I'm pretty sure there are still plenty of others I fortunate enough to have not met yet. But I will be sure to update this post when I encounter one.
Once again, how I wrote and explained things are actually how I think in my mind, so some part might be confusing or just wrong. Please let me know by emailing me at tri@trile.cloud or just connect me on any social platform in the footer. I would love to hear from your insightful messages to improve this post.
Thanks for reading!