JavaScript Render modes
Monolithic application server
In a traditional monolithic architecture there is an application server that serves all the requests (HTTP and Ajax) where the output can be HMTL and JSON. Static files can be saved in a proxy or CDN (Content Delivery Network) and generated HTML can also be cached by a proxy and easily parsed by SEO Bots.

Single page applications/Serverless
Recent single page applications powered by frameworks like React or Angular are entirely based on JavaScript, the entire UI is generated by the Browser. The code is saved in a Proxy/CDN fetched by the browser that runs it locally, access to other resources can be made entirely using HTTP/JSON requests.
This Serverless architecture is quite efficient and cost-effective, as all content is static, in fact, micro-services can be built using Function-as-an-service frameworks like AWS Lambda erasing the need for an application server.
But there is a drawback, generated dynamically the UI puts pressure on the client and HTML cannot be cached on a Proxy, only data from microservices can be cached what doesn't eliminate the need for the browser to handle and process it.
SEO management is also next to impossible as there's no HTML to start with, therefore relying in JS frameworks to build sites with static content can be a problem.

Static and server side rendering
Frameworks like Gatsby or Next.JS enable different render modules where HTML content can be pre-generated before being sent to the client, therefore allowing the sites to be cached and became SEO-friendly.
There are two modes:
Build time Static Generation
Relying on the sophistication of build pipelines, the build process can generate HTML as regular output as an pre-processing task, this can be done with minimal changes using the same code and data structures used in the dynamic counter part.
This is a quite simple and cost-effective strategy but it requires a new build to change the UI also doesn't differentiate between requests.
NextJS
export async function getStaticProps(context) {
return {
props: {}, // will be passed to the page component as props
}
}
export async function getStaticPaths() {
return {
paths: [
{ params: { ... } } // See the "paths" section below
],
fallback: true or false // See the "fallback" section below
};
}

Server-side Generation (request-time)
This mode enables to part of the code to be rendered at request time, therefore is more flexible and customizable than Static generation, integration is also simple, code used for dynamic JavaScript can used in Server-side generation.
The biggest disadvantage of this strategy is that requires an application server (NodeJS or Vercel) to process and render the requests.
NextJS
export async function getServerSideProps(context) {
return {
props: {}, // will be passed to the page component as props
}
}
