Introduction
Project Setup
bash npx create-next-app@latest next-ssr-production --ts cd next-ssr-production
<h3>Essential Dependencies</h3> <p>Install additional packages that help with SSR, image optimization, and environment management.</p>bash npm i axios swr next‑image‑optimizer dotenv npm i -D @types/node
<h3>Configuring <code>next.config.js</code></h3> <p>The configuration file tells Next.js how to handle image domains, compression, and output directories for a production build.</p>/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
images: {
domains: ['images.unsplash.com', 'your-cdn.com'],
},
// Enable incremental static regeneration (ISR) fallback for SSR pages
experimental: {
appDir: true,
},
// Set custom build output folder
distDir: 'build',
};
module.exports = nextConfig;
<h3>Environment Variables</h3> <p>Create a <code>.env.production</code> file for credentials that the server will consume. Never expose secrets to the client bundle.</p>dotenv
.env.production
API_BASE_URL=https://api.mycompany.com NEXT_PUBLIC_ANALYTICS_ID=UA-XXXXX-Y
<p>Next.js automatically loads <code>.env*</code> files based on the runtime environment. Access them using <code>process.env</code> inside <code>getServerSideProps</code> or API routes.</p>Production Architecture
tsx // pages/products/[id].tsx import { GetServerSideProps, NextPage } from 'next'; import axios from 'axios'; import Image from 'next/image';
interface ProductProps { product: { id: string; name: string; price: number; imageUrl: string; description: string; }; }
const ProductPage: NextPage<ProductProps> = ({ product }) => { return ( <main className="container mx-auto p-4"> <h1 className="text-3xl font-bold mb-4">{product.name}</h1> <Image src={product.imageUrl} alt={product.name} width={800} height={600} className="rounded-md" /> <p className="mt-4">{product.description}</p> <p className="mt-2 text-xl font-semibold">${product.price}</p> </main> ); };
export const getServerSideProps: GetServerSideProps = async (context) => {
const { id } = context.params!;
const res = await axios.get(${process.env.API_BASE_URL}/products/${id});
if (res.status !== 200) {
return { notFound: true };
}
return { props: { product: res.data } };
};
export default ProductPage;
<p>This page demonstrates a classic SSR workflow: data is fetched on the server, the HTML is streamed, and the client receives a fully‑rendered page on first load.</p>Performance Optimizations
// next.config.js (excerpt)
module.exports = {
experimental: {
reactRoot: true,
serverComponents: true,
// Activate streaming for Node.js runtime
streaming: true,
},
};
<h3>3. Compression & HTTP/2</h3>
<p>Deploy on platforms that automatically apply Brotli compression and HTTP/2 multiplexing. If you manage your own server (e.g., Nginx), add the following snippet:</p>
nginx
nginx.conf - enable brotli compression
brotli on; brotli_comp_level 6; brotli_types text/plain text/css application/javascript application/json image/svg+xml;
<h3>4. Image Optimization</h3> <p>Leverage <code>next/image</code> which automatically serves responsive, WebP‑converted images from the edge. Configure domains and set device‑size breakpoints.</p>// next.config.js (image section)
images: {
deviceSizes: [320, 420, 768, 1024, 1200],
imageSizes: [16, 32, 48, 64, 96],
remotePatterns: [{
protocol: 'https',
hostname: 'images.unsplash.com',
}],
},
<h3>5. Monitoring & Error Handling</h3>
<p>Integrate a performance monitoring service (e.g., Vercel Analytics, New Relic, or Datadog) to track SSR latency, cache hit ratios, and error rates. Wrap <code>getServerSideProps</code> in a try/catch block and log failures without breaking the user experience.</p>
tsx export const getServerSideProps: GetServerSideProps = async (ctx) => { try { // fetch data } catch (error) { console.error('SSR error:', error); return { props: { error: 'Failed to load data' } }; } };
<p>By applying these tactics, you can keep your Next.js SSR service resilient, fast, and ready for production traffic.</p>