Why Use Kamal for Deployment?
So, why pick Kamal for your deployments?
Simple: it makes the process smooth, fast, and reliable—without locking you into a complicated toolchain. Here’s what makes Kamal shine:
- Readable YAML configs: Easy to write, easy to understand.
- First-class Docker support: Get consistent builds wherever you deploy.
- Rolling deployments: No downtime. No late-night fire drills.
- Built-in health checks: Kamal keeps an eye on your app so you don’t have to.
Whether you're shipping fast or scaling up, Kamal helps you stay in control.
What You’ll Need Before You Start
Before jumping in, make sure your dev environment’s good to go:
- An AWS account, with the CLI set up
- Docker installed (and basic CLI comfort)
- Kamal version 2.4 or higher
- A working Next.js app
- Some GitHub Actions knowledge
Step 1: Initialize Kamal in Your Project
Start by initializing Kamal in your app repo. Run:
kamal init
This sets up a .kamal
directory with the core config files you’ll customize next.
Project Structure Overview
Here’s what your project directory should look like after setup:
project-root/ ├── .kamal/ # Kamal deployment config │ ├── deploy.yml # Main deployment settings │ └── secrets # Environment secrets ├── .github/workflows/ # CI/CD pipelines │ └── release-deploy.yml # GitHub Actions workflow ├── Dockerfile # Production build setup ├── package.json # Dependencies ├── yarn.lock # Lockfile ├── .env # Local environment variables ├── public/ # Static assets └── .next/ # Compiled Next.js output
Example deploy.yml
for Kamal
Here’s a sample deploy.yml
config tuned for staging:
defaults: service: web-app image: example/web-app servers: web: - 192.168.1.1 # Replace with your staging server IP 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
Building a Dockerfile for Next.js
Here’s a lean, production-ready Dockerfile for a Next.js app:
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"]
This sets you up for reproducible builds and fast deployment.
Automating Deployments with GitHub Actions
Want your app to deploy automatically when a new release is published? Here’s a GitHub Actions workflow that gets the job done:
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 }}
This pipeline checks out your code, configures AWS credentials, builds the Docker image, and pushes it straight to your ECR registry—all triggered by a GitHub release.
Wrapping Up
And there you have it: a solid deployment workflow using Kamal 2.4, Docker, and GitHub Actions.
You’ve got:
- A clean, reproducible setup
- Auto-deployments on release
- A scalable, self-hosted Next.js app on AWS
No vendor lock-in. No drama. Just fast, predictable deployments.
Top comments (0)