Docker

Containerizing application for production

./Dockerfile
# Install Packages FROM node:16-alpine AS deps RUN apk add --no-cache libc6-compat WORKDIR /app COPY package*.json ./ RUN npm i

Dockerizing 1st stage

I employed the Next.js configuration output standalone feature in conjunction with a multistage Dockerfile. The FROM node:16-alpine instruction is to determine the parent image for the application. For clarity, the first stage of this process involves copying the package.json file and installing the necessary node_modules dependencies.

./Dockerfile
# Build stage FROM node:16-alpine AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . RUN npm run build

Dockerizing 2nd stage

The 2nd stage involves copying the `node_modules` from the 1st stage. Secondly, it copies the source TypeScript code and then compiles it into JavaScript. This is achieved using the TypeScript compiler or the `tsc` command. Next, the Next.js build process analyzes the `pages` directory for any exported components, creating a route for each one. The framework also applies optimizations on the generated JavaScript code and other assets, resulting in a more efficient build output. Finally, the build generates a `.next` folder which contains the optimized and standalone build output.

./Dockerfile
# Production image, copying only standalone and static .next FROM node:16-alpine AS runner WORKDIR /app ENV NODE_ENV production RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs COPY --from=builder /app/public ./public COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static USER nextjs EXPOSE 3000 CMD ["node", "server.js"]

Dockerizing 3rd stage

In the final and 3rd stage, the dockerizing process copies over the optimized and standalone version of the server which includes the `.next` directory required chunks for the runtime, skipping dev packages and unnecessary artifacts. This technique results in a lightweight and high performing build, improving the overall efficiency of the container. By using this methodology, we obtain an efficient and powerful solution for creating high-quality, production-ready Next.js applications written in TypeScript.