DEV Community

Cover image for How to deploy a Nextjs app with Kamal 2.4, AWS ECR, and Github Actions
Derick Zihalirwa
Derick Zihalirwa

Posted on • Edited on

1 1 1

How to deploy a Nextjs app with Kamal 2.4, AWS ECR, and Github Actions

Why Use Kamal for Deployment?

Wondering why Kamal is the right choice? Kamal makes your deployments stress-free and efficient. Here’s how:

  • Kamal uses clean, YAML-based config files that are easy to set up and manage.
  • Seamlessly integrates with Docker for consistent builds, no matter where you deploy.
  • Enjoy rolling deployments that keep your app running smoothly—no more midnight emergencies.
  • Kamal constantly monitors your app’s health so you can rest easy.

What You Need Before Starting

Let’s make sure you’re all set before we start:

  • AWS account + CLI configured
  • Docker installed (know your way around basic commands)
  • Kamal 2.4 or later
  • Familiarity with GitHub Actions
  • A Next.js app ready to rock

Initializing Kamal in Your Project

Before diving into configuration, you need to initialize Kamal in your project. This sets up the necessary directory structure and files. Run the following command inside your project repository:

kamal init
Enter fullscreen mode Exit fullscreen mode

This command will create a .kamal directory with the initial configuration files you'll customize later.


Project Structure Breakdown

Here’s a quick peek at how your project should look:

project-root/
├── .kamal/                   # Kamal config
│   ├── deploy.yml            # Deployment settings
│   └── secrets               # Secrets storage
├── .github/workflows/        # GitHub Actions workflows
│   └── release-deploy.yml    # Auto-deployment script
├── Dockerfile                # Docker build instructions
├── package.json              # Dependencies
├── yarn.lock                 # Lock file
├── .env                      # Local env variables
├── public/                   # Static assets
└── .next/                    # Compiled Next.js build
Enter fullscreen mode Exit fullscreen mode

Example deploy.yml (Kamal Configuration)

defaults:
  service: web-app
  image: example/web-app

servers:
  web:
    - 192.168.1.1

ssh:
  user: ubuntu
  keys: ["~/.ssh/example-key.pem"]

proxy:
  ssl: false
  app_port: 3000
  host: stagingapp.example.io
  healthcheck:
    path: /
    interval: 3
    timeout: 30

registry:
  server: 123456789012.dkr.ecr.us-west-1.amazonaws.com
  username: AWS
  password: <%= %x(aws ecr get-login-password) %>

builder:
  arch: amd64
  context: .

env:
  clear:
    NEXT_PUBLIC_APP_BACKEND_URL: https://staging.api.example.io
    NEXT_PUBLIC_APP_PUBLIC_IP_API: https://pro.ip-api.com/json/?key=dummykey
Enter fullscreen mode Exit fullscreen mode

Building the Dockerfile

Here’s a lean Dockerfile for production-ready Next.js apps:

FROM node:lts-bookworm-slim AS base

FROM base AS deps
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
ARG NEXT_PUBLIC_APP_BACKEND_URL
ARG NEXT_PUBLIC_APP_PUBLIC_IP_API
ENV NEXT_PUBLIC_APP_BACKEND_URL=$NEXT_PUBLIC_APP_BACKEND_URL
ENV NEXT_PUBLIC_APP_PUBLIC_IP_API=$NEXT_PUBLIC_APP_PUBLIC_IP_API

COPY . .
RUN yarn run build

FROM base AS release
WORKDIR /app
ENV NEXT_TELEMETRY_DISABLED=1
COPY --from=deps /app/node_modules ./node_modules
COPY --from=deps /app/package.json ./package.json
COPY --from=deps /app/.next ./.next
COPY --from=deps /app/public ./public

EXPOSE 3000
CMD ["yarn", "start"]
Enter fullscreen mode Exit fullscreen mode

Automating with GitHub Actions

Time to make deployments automatic! Here’s a GitHub Actions workflow you can use:

name: Release Deploy

on:
  release:
    types: [published]

permissions:
  contents: read
  packages: write
  id-token: write

env:
  ECR_REPOSITORY: example/web-app

jobs:
  package:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Create .env file
        run: |
            echo "${{ secrets.PROD_ENV_FILE }}" > .env

      - name: Configure AWS
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
          aws-region: us-west-1

      - name: Login to ECR
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build & Push Docker Image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./Dockerfile
          platforms: linux/amd64
          push: true
          tags: |
            ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }}
Enter fullscreen mode Exit fullscreen mode

Wrapping Up

And that’s it! Kamal 2.4 makes self-hosting Next.js apps on AWS ECR a breeze. With GitHub Actions handling the automation, deployments are seamless.

Postgres on Neon - Get the Free Plan

No credit card required. The database you love, on a serverless platform designed to help you build faster.

Get Postgres on Neon

Top comments (0)

Cloudinary image

Video API: manage, encode, and optimize for any device, channel or network condition. Deliver branded video experiences in minutes and get deep engagement insights.

Learn more

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay