KubeKanvas Logo
FeaturesPricingTemplatesBlogFAQsContactBook a Demo
Book a Demo
FeaturesPricingTemplatesBlogFAQsContactBook a Demo

Building and Deploying a Modern Blog Platform with Next.js, Strapi, and Kubernetes – Part 2: Adding the Frontend

Deploy Next.js + Strapi blog on Kubernetes with Docker, Ingress routing, and service discovery. Complete tutorial for modern headless CMS deployment.

Shamaila Mahmood

Shamaila Mahmood

July 29, 2025

Cloud-Native Web Applications
Strapi and NextJS on Kubernetes - Part 2

Step 1: Why Next.js?

When building a frontend for a blog, you want more than just a beautiful UI—you want speed, discoverability, and reliability.

Next.js is ideal for this because it offers:

  • SEO Optimization: With static site generation (SSG) and server-side rendering (SSR), your blog content is indexable by search engines—critical for visibility.
  • Fast Performance: Pages load quickly, especially when statically generated, improving both UX and SEO ranking.
  • Flexible Rendering Options: Mix SSG and SSR depending on content type.
  • Developer Experience: File-based routing, TypeScript support, and hot reloading make Next.js incredibly productive.
  • API Routes: Backend logic (like preview endpoints) can live alongside your frontend.

For a blog, where search engine visibility and snappy content delivery matter, Next.js is the gold standard.

Understanding the Architecture

Before we dive into deployment, let's understand how our Next.js frontend will interact with Strapi:

  1. Content Fetching: Next.js will make HTTP requests to Strapi's REST API or GraphQL endpoint to fetch blog posts, author information, and media
  2. Static Generation: At build time, Next.js can pre-generate pages using Strapi content, resulting in lightning-fast page loads
  3. Dynamic Rendering: For real-time content or personalized experiences, Next.js can fetch data on each request
  4. Media Handling: Images and other media stored in Strapi will be referenced and optimized by Next.js

This architecture gives you the best of both worlds: the editorial experience of a traditional CMS with the performance and developer experience of a modern frontend framework.


Step 2: Building the Next.js Application

Creating the Frontend Application

First, let's understand what goes into a typical Next.js blog application that connects to Strapi:

Key Components:

  • Pages: Blog listing, individual blog posts, author pages
  • Components: Headers, footers, blog post cards, navigation
  • Data Fetching: Functions to communicate with Strapi API
  • Image Optimization: Next.js Image component for performance

Sample Next.js Project Structure

💡 Complete Source Code Available: You can find the complete, working Next.js frontend code in our GitHub repository: Github repo link

blog-frontend/
├── components/
│   ├── BlogCard.tsx      # Blog post preview cards with modern styling
│   └── Layout.tsx        # Site layout with sticky header and footer
├── lib/
│   └── strapi.ts         # GraphQL client and API functions
├── pages/
│   ├── _app.tsx          # Next.js app component
│   ├── index.tsx         # Homepage with hero section and blog grid
│   └── blog/
│       └── [slug].tsx    # Individual blog post pages
├── styles/
│   ├── globals.css       # Tailwind CSS imports and custom styles
├── tailwind.config.js    # Tailwind CSS configuration
├── postcss.config.js     # PostCSS configuration
├── Dockerfile            # Container configuration
├── next.config.js        # Next.js configuration
├── package.json          # Dependencies and scripts
└── tsconfig.json         # TypeScript configuration

The Next.js frontend connects to Strapi using GraphQL with proper authentication. The key integration points are:

Environment Variables Required:

  • NEXT_PUBLIC_STRAPI_URL - Your Strapi backend URL
  • NEXT_PUBLIC_STRAPI_TOKEN - API token for authentication with Strapi GraphQL endpoint

Key Features:

  • GraphQL client with Bearer token authentication
  • TypeScript interfaces matching Strapi's schema structure
  • Static site generation for optimal performance

💡 Complete Source Code Available: You can find the complete, working Next.js frontend code in our GitHub repository: Github repo link

The repository includes:

  • Full Next.js application
  • GraphQL integration with Strapi
  • Docker configuration for containerization
  • All necessary configuration files

Important to note is the use of environment variable NEXT_PUBLIC_STRAPI_URL. This contains the URL of the Strapi deployment and the NEXT_PUBLIC_STRAPI_TOKEN for authentication.

Building the Docker Image

Your Next.js application needs to be containerized for Kubernetes deployment. The Docker setup uses a multi-stage build process for optimal production deployment:

Why Use Next.js Standalone Server?

We're using Next.js standalone output mode, which creates a self-contained deployment that includes all necessary dependencies. This approach provides several advantages:

  1. Simplicity: Single Node.js process handles all requests, no need for nginx configuration
  2. Flexibility: Full Next.js features including API routes and middleware
  3. Developer Experience: Easier debugging and development alignment
  4. Modern Approach: Recommended by Vercel for containerized deployments
  5. Resource Efficiency: Optimized standalone output with minimal dependencies

Standalone Server Configuration

The next.config.js is configured with output: 'standalone', which creates a minimal production server. Environment variables are embedded at build time for security and performance.

The repository contains a docker file, use the docker file to create and run or publish the image.

Build and push your image:

# Build the image with environment variables
docker build \
  --build-arg NEXT_PUBLIC_STRAPI_URL=http://strapi-service:1337 \
  --build-arg NEXT_PUBLIC_STRAPI_TOKEN=your-api-token \
  -t yourdockerhub/nextjs-blog:latest .

# Test the image locally (optional)
docker run -p 3000:3000 yourdockerhub/nextjs-blog:latest

# Push to registry
docker push yourdockerhub/nextjs-blog:latest

Step 3: Deploying the Next.js Frontend

Now let's deploy the containerized Next.js application to Kubernetes. Here's an enhanced deployment with production-ready configurations:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: blog-frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: blog-frontend
  template:
    metadata:
      labels:
        app: blog-frontend
    spec:
      containers:
        - name: nextjs
          image: yourdockerhub/nextjs-blog:latest
          ports:
            - containerPort: 3000

Understanding the Standalone Server Deployment:

We're using Next.js standalone server mode, where the environment variables (NEXT_PUBLIC_STRAPI_URL and NEXT_PUBLIC_STRAPI_TOKEN) are embedded into the standalone output during the Docker build process. This means:

  1. Build-time Configuration: The Strapi URL and token are set when building the Docker image using --build-arg
  2. No Runtime Environment Variables: The running container doesn't need these variables since they're already compiled into the standalone server
  3. Port 3000: Next.js standalone server runs on port 3000

This deployment connects the frontend to the Strapi backend using strapi-service (strapi-service:1337). Remember we created this service in the Part 1. In your deployment of Strapi you also need to install GraphQL plugin to be able to query Strapi through GraphQL.

Strapi NextJS Ingress Architecture Diagram

Copy-Pasting sounds boring and outdated? Try our ready template

Start with the template that I have written specially to deploy Strapi/Next application in Kubernetes. Do not waste your time copy-pasting them.

Use Template Now

Just like with Strapi, the Next.js frontend must also be exposed via a Kubernetes Service. This allows other resources—such as an Ingress—to reach the application reliably.

In the service definition below, the selector field must match the matchLabels used in the frontend deployment, ensuring traffic is routed to the correct pods. Similarly, the targetPort must match the containerPort defined inside the deployment. These values ensure that network communication from Kubernetes Services correctly maps onto your running containers.

apiVersion: v1
kind: Service
metadata:
  name: frontend-service
  labels:
    app: blog-frontend
spec:
  type: ClusterIP
  selector:
    app: blog-frontend
  ports:
    - name: http
      protocol: TCP
      port: 3000
      targetPort: 3000

Understanding Kubernetes Services

A Service in Kubernetes provides several critical functions:

  1. Service Discovery: Other pods can find your application using the service name (blog-frontend)
  2. Load Balancing: If you scale to multiple pods, the service automatically distributes traffic
  3. Stable Networking: Even if pods are recreated, the service provides a consistent endpoint
  4. Port Abstraction: External clients don't need to know which port the container is actually listening on

In the service definition above:

  • selector: Must match the matchLabels used in the deployment
  • port: The port that other services will use to connect
  • targetPort: The actual port your application listens on inside the container

Apply the service:

kubectl apply -f blog-frontend-service.yaml

Test the service internally:

# Get a shell in any pod in the cluster
kubectl run -it --rm debug --image=busybox --restart=Never -- sh

# From inside the pod, test the service
wget -qO- http://frontend-service:3000

Now as in previous article (Part 1) we used port forwarding to view the application running in browser, you can do the same to access your frontend in your browser.

kubectl port-forward service/frontend-service 8080:3000

In real setups this is not what you would like to do. We create software so that others can use it and not to run on local. To make the application available without port-forwarding, we need to make it accessible from outside the cluster. One way of doing so is with NodePort service. Another way is with Ingress.

What is Ingress

Ingress is Kubernetes' way of managing external access to services in your cluster, typically HTTP and HTTPS traffic. Think of it as a smart reverse proxy that sits at the edge of your cluster and routes incoming requests to the right services based on rules you define. Unlike NodePort services that expose individual services on random high ports, Ingress gives you clean URLs and can handle multiple services through a single entry point. It also provides advanced features like SSL termination, path-based routing, and load balancing - making it the preferred way to expose web applications to the internet.

Install NGINX Ingress Controller for Docker Desktop

Before we start configuring Ingress we need to install Ingress Controller in our cluster. Following is the command to install Ingress Controller in Docker Desktop.

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/cloud/deploy.yaml

Wait for it to be ready

kubectl wait --namespace ingress-nginx --for=condition=ready pod --selector=app.kubernetes.io/component=controller --timeout=300s

Step 5: Configure Ingress for Public Access

So far, we've been using port-forwarding to access both Strapi and our Next.js frontend. While this works for development, we need to configure Ingress to make both applications accessible from the internet. We'll set up routing rules so that Strapi (for the admin interface) and the Next.js frontend (for the public blog) are both available through clean URLs.

Understanding Ingress Path Routing

Kubernetes Ingress allows you to route HTTP/HTTPS traffic based on the request path:

  • Path-based routing: Different URLs go to different services
  • Host-based routing: Different domains go to different services
  • Priority: More specific paths take precedence over general ones

In our case:

  • /admin → Routes to Strapi for content management
  • / → Routes to Next.js frontend for the public blog

Updated Ingress Configuration

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: blog-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
    - http:
        paths:
          # Strapi admin interface
          - path: /admin
            pathType: Prefix
            backend:
              service:
                name: strapi-service
                port:
                  number: 1337
          # Next.js frontend (catch-all)
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend-service
                port:
                  number: 3000

Understanding Path Priority

The order of paths in the Ingress matters:

  1. Most specific first: /admin is more specific than /
  2. Catch-all last: / will match any path that doesn't match the above

This ensures that:

  • yourdomain.com/admin → Goes to Strapi admin
  • yourdomain.com/, yourdomain.com/blog/my-post → Goes to Next.js

Apply the updated Ingress:

kubectl apply -f blog-ingress.yaml

Step 6: Testing the Complete Setup

Verify Ingress Controller

First, make sure your Ingress controller is running and has an external IP:

kubectl get ingress blog-ingress
kubectl get services -n ingress-nginx

Test Different Endpoints

Once your Ingress has an external IP, test different paths:

# Get the Ingress IP
export INGRESS_IP=$(kubectl get ingress blog-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')

# Test the frontend
curl http://$INGRESS_IP/

# Test Strapi admin (should redirect to login)
curl http://$INGRESS_IP/admin


Meanwhile, /admin will still take you to the Strapi CMS interface for content management.

The following diagram cleanly describes what we have done so far.


Strapi NextJS Ingress Architecture Diagram

Conclusion

Congratulations! You've successfully built and deployed a complete blog platform with Next.js frontend and Strapi CMS backend running on Kubernetes. In this part, we accomplished several key milestones:

  • Deployed a Next.js frontend that connects to your Strapi backend via GraphQL/REST APIs
  • Configured Kubernetes Services for reliable internal communication between components
  • Set up Ingress routing to expose both the public blog and admin interface through clean URLs
  • Implemented path-based routing so /admin goes to Strapi, and / displays your beautiful blog
  • Learned production deployment patterns including multi-stage Docker builds and service discovery

Your blog is now functional and accessible to you without port-forwarding! However, there's still one critical limitation: your content disappears every time the Strapi pod restarts because we're still using Strapi's default in-memory database inside the container.

Coming up in Part 3: We'll make your blog truly production-ready by configuring a persistent PostgreSQL database to ensure your content survives pod restarts, and we'll set up AWS S3 for reliable media storage so your images and files are safely stored outside the cluster. No more losing your hard work when Kubernetes reschedules pods!

Kubernetes

Related Articles

Kubernetes Architecture Series – Part 2: Designing Scalable and Resilient Applications
Kubernetes Architecture Series – Part 2: Designing Scalable and Resilient Applications

This is the second part of our three-part Kubernetes architecture series.

Khurram Mahmood

Khurram Mahmood

July 27, 2025

Kubernetes Architecture
Building a Modern Blog with Strapi & Kubernetes: Your First CMS in the Cloud
Building a Modern Blog with Strapi & Kubernetes: Your First CMS in the Cloud

Learn how to build and run a modern blog CMS using Strapi in Kubernetes. This first part walks you t...

Shamaila Mahmood

Shamaila Mahmood

July 23, 2025

Cloud-Native Web Applications
Kubernetes Architecture Series - Part 1: From Containers to Cloud-Native Orchestration
Kubernetes Architecture Series - Part 1: From Containers to Cloud-Native Orchestration

Part 1 of the three-part blog series on Kubernetes architecture

Khurram Mahmood

Khurram Mahmood

July 23, 2025

Kubernetes Architecture
Deep Dive: The Magic Behind KubeKanvas – Feature by Feature
Deep Dive: The Magic Behind KubeKanvas – Feature by Feature

Visualize, validate, and deploy Kubernetes configs with ease—discover the power of KubeKanvas beyond...

Essa Hashmi

Essa Hashmi

July 15, 2025

KubeKanvas Features
KubeKanvas Logo

Visual Kubernetes cluster design tool that helps you create, manage, and deploy your applications with ease.

Product

  • Features
  • Pricing
  • Templates

Resources

  • Blog
  • Tutorials

Company

  • About Us
  • Contact
  • Terms of Service
  • Privacy Policy
  • Impressum
XGitHubLinkedIn
© 2025 KubeKanvas. All rights reserved.