Initializing Next.js 13 with Pino Logging and Docker Deployment

Khan
Goalist Blog
Published in
4 min readFeb 14, 2024

Welcome to our latest blog post, where we explore the process of initializing a Next.js 13 application, configuring Pino for logging, and setting up a Docker for deployment.
Whether you’re a seasoned developer looking to explore the latest features of Next.js or just getting started with web development, this step-by-step tutorial will help you kickstart your project with confidence.

1. Create Next.js 13

Firstly, we need to create the Next.js source. The Next team recommends using the command below to start a new Next.js app,
so everything will be done automatically:
npx create-next-app@latest
After the “@” symbol, the specified version is “latest”
Just a note from my side: if your goal is learning, you can experience the latest version.
However, if it is an actual project, it is advisable to use the stable version.

2. Install Pino for logger

As I explored the internet, I noticed that a significant number of individuals advocate for using Pino as the preferred logging tool.
Pino is also the logging tool of choice for my team, and I would like to provide some insights about its usage now.

Pino is a powerful logging framework for Node.js, known for its outstanding speed and comprehensive features.
With Pino, you gain the ability to:

Set the logging level of each module without modifying the module’s code.
Utilize multiple log transportation options, including files and console logs.

For my actual projects, the Next.js middleware is the best place to add logging to your Next.js application.

Are you familiar with middleware in Next.js?
It’s a feature that empowers developers to intercept, modify, and control the flow of API requests and responses in their applications.
We invoke logger in middleware to track the API requests and responses.

Let’s proceed with the following steps.

2.1 The following command is to install pino:
npm install pino

2.2 Log Level Configuration
Let’s create a file with the content below:
There are no constraints on naming the file. Now, I’ve simply named it: “logLevel.ts”.

const logLevelData = {
“*”: “silent”,
“home”: “info”,
}

export default logLevelData

2.3 Define the logging utility functions
I create a file named “logUtil.ts” as below.

import logLevelData from “./logLevel”;
import pino, { Logger } from “pino”;

const logLevels = new Map<string, string>(Object.entries(logLevelData));

export function getLogLevel(logger: string): string {
return logLevels.get(logger) || logLevels.get(“*”) || “info”;
}

export function getLogger(name: string): Logger {
return pino({ name, level: getLogLevel(name) });
}

2.4 Define a function to custom log API request and response.
To customize the log as needed, I have also created a file named “requestLog.ts” as shown below.

import { NextRequest, NextResponse } from “next/server”;
import { getLogger } from “./logUtil”;

export default function requestLogger(request: NextRequest, response: NextResponse) {

const time = Date.now();
const timeStr = new Date(time).toLocaleDateString();

const logger = getLogger(“home”);

const logData = `[${timeStr}] Request Url: ${request.url} — HOST ${request.headers.get(“Host”)} — Agent: ${request.headers.get(“User-Agent”)}`;
const responseData = `[${timeStr}] Response: ${response.url} — Status: ${response.status} — Error: ${response.statusText}`;
logger.info(logData);
logger.info(responseData);
}

2.5 Invoke the above requestLogger in middleware.ts

export default async function middleware(request: NextRequest) {
const response = NextResponse.next();

// Logger Middleware
requestLogger(request, response);

return response;
}

3. Set up docker to deploy

It’s time to deploy
As a developer, have you experienced situations where something works on your computer but not on your team members’ computers?
Yes, that’s one of the reasons Docker was created. It packages code and dependencies into containers that function identically across multiple environments.

On the official Docker website, we can find comprehensive detailed information about containerized applications.
Allow me to summarize the steps and provide some additional notes.

- Install Docker
- Create a Dockerfile
- Set up an ignore file
- Update Next.js Configurations
- Build the Docker Image
- Run the Docker Container
Now, We have containerize out Next.js application.
so We see the running application.

There are some common pitfalls to be mindful of.

3.1 In a Dockerfile, the FROM instruction specifies the base image from which you are building your Docker image.
A compromised base image could contain malware that attacks your application, so try to use Docker Hub images that are marked as official or submitted by a verified publisher.

3.2 Adding HEALTHCHECK instruction to enable health checks for your application.
HEALTHCHECK — timeout=3s CMD curl -f http://localhost || exit 1

This instruction sets up a health check using the curl command to send an HTTP GET request to http://localhost.
The -f flag is used with curl to return an error if the requested URL is not found (HTTP 404).
If the request fails or the response is not successful within the specified timeout period (3 seconds in this case), the health check will fail, and the container will be considered unhealthy (exit 1).

3.3 CMD and ENTRYPOINT are two instructions that together define the command that runs when your container starts.
The ENTRYPOINT instruction sets the primary command that is executed when the container starts.
The CMD instruction provides default arguments for the command specified by ENTRYPOINT, or sets the default command to be executed if no ENTRYPOINT is defined.

Let’s examine the following example:

FROM ubuntu
ENTRYPOINT [“echo”, “Hello”]
CMD [“World”]

Now, we’ll build the image and run the container using docker run.
docker build -t entrypoint-cmd
docker run entrypoint-cmd

The output ‘Hello World’ is generated by executing the command specified in the ENTRYPOINT, followed by the additional arguments provided in the CMD instructions.

Get ready to embark on an exciting journey into the world of Next.js development, armed with the knowledge to streamline your application setup and deployment process.
With these foundational steps in place, you’re well-equipped to build your own web applications efficiently.
Stay inspired and keep coding!

--

--

Khan
Goalist Blog

“A journey of a thousand miles begins with a single step”