- Published on
How to deploy a Next.js app with Prisma and Postgres using Coolify
The promise was to be able to deploy a Next.js app easily like to Vercel. But it turned out it was not so easy.
- Authors
- Name
- Nico Prananta
- Follow me on Bluesky
Ever since the drama around Vercel pricing, Coolify has become a popular choice for self-hosting. Coolify makes it easy to deploy web apps on your own server with just a few clicks. It was created to challenge hosting platforms like Vercel, which are famous for their ease of use but tend to be pricey. However, as I suspected, self-hosting is not as easy as some people make it out to be.
Deploying a static Next.js app via Coolify is indeed straightforward. I moved my Pull Request Best Practices book website from Vercel to my own server using Coolify. You just need to add the repository URL of your project to the Coolify dashboard. Then, you can click the "Deploy" button. Coolify will automatically build your app and deploy it to your server.
But what if you want to deploy a Next.js app with Prisma and Postgres? It turns out it's not that easy. I encountered several annoying problems, and I'm going to share my experience with you so that you can learn from it.
Image
First, I installed and deployed a Postgres database from the Coolify dashboard. Once it was running, Coolify exposed the internal URL of the Postgres instance, which I used as an environment variable for the Next.js app. I then tried to deploy the app via the Coolify dashboard and immediately hit the first problem.
Before building the app, my project needed to run Prisma migration first. But for some reason, it could not reach the database instance during the build.
13 1.227 > prisma migrate deploy
13 1.227
13 2.087 Environment variables loaded from .env
13 2.088 Prisma schema loaded from prisma/schema.prisma
13 2.092 Datasource "db": PostgreSQL database "postgres", schema "public" at "ycskg0w:5432"
13 2.195
13 2.196 Error: P1001: Can't reach database server at `ycskg0w:5432`
13 2.196
13 2.196 Please make sure your database server is running at `ycskg0w:5432`.
I ensured the database was running and accessible. So I assumed the error occurred because the build container wasn't in the same network as the database container. Unfortunately, I forgot what I did next, but I managed to configure the build container to reach the database container.
However, I soon encountered another problem: I got a "Schema engine error" without any further information. I found other people had a similar problem because Nixpacks doesn't support Prisma yet.
Eventually, I managed to deploy the app by ditching Nixpacks and using the following Dockerfile instead:
FROM node:18-alpine AS base
# Step 1. Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
# Omit --production flag for TypeScript devDependencies
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i; \
else echo "Warning: Lockfile not found. It is recommended to commit lockfiles to version control." && yarn install; \
fi
# Adjust the files and folders that should be copied to the build container
COPY app ./app
COPY public ./public
COPY components ./components
COPY lib ./lib
COPY next.config.mjs .
COPY prisma ./prisma
COPY components.json .
COPY tailwind.config.ts .
COPY tsconfig.json .
COPY postcss.config.mjs .
# Environment variables must be present at build time
ARG DATABASE_URL
ENV DATABASE_URL=${DATABASE_URL}
ARG BASIC_AUTH_USER
ENV BASIC_AUTH_USER=${BASIC_AUTH_USER}
ARG BASIC_AUTH_PASSWORD
ENV BASIC_AUTH_PASSWORD=${BASIC_AUTH_PASSWORD}
# Build Next.js based on the preferred package manager
RUN \
if [ -f yarn.lock ]; then yarn build; \
elif [ -f package-lock.json ]; then npm run build; \
elif [ -f pnpm-lock.yaml ]; then pnpm build; \
else npm run build; \
fi
# Step 2. Production image, copy all the files and run next
FROM base AS runner
RUN apk --no-cache add curl
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
USER nextjs
COPY /app/public ./public
# Automatically leverage output traces to reduce image size
COPY /app/.next/standalone ./
COPY /app/.next/static ./.next/static
# Environment variables must be redefined at run time
ARG DATABASE_URL
ENV DATABASE_URL=${DATABASE_URL}
ARG BASIC_AUTH_USER
ENV BASIC_AUTH_USER=${BASIC_AUTH_USER}
ARG BASIC_AUTH_PASSWORD
ENV BASIC_AUTH_PASSWORD=${BASIC_AUTH_PASSWORD}
EXPOSE 3000
ENV PORT 3000
CMD HOSTNAME=0.0.0.0 node server.js
Here were the important steps:
- I need to set the Next.js build output as
standalone
by updating thenext.config.mjs
file.
const nextConfig = {
output: 'standalone',
// ...
}
- I need to set the
DATABASE_URL
environment variable to the internal URL of the Postgres database instance exposed by Coolify. - In the Coolify dashboard of the project, select "Dockerfile" as the Build Pack.
- Add that Dockerfile to the repository and push it to the repository. Coolify will automatically build the app and deploy it to your server successfully.
You can find the repository of the project here and the deployed app here.
Should you self-host?
While I learned several things from this experience and from my previous experience deploying Minio via Coolify, I maintain my position that self-hosting is never easy. Tools like Coolify indeed make it easier to deploy web apps, but they are not a silver bullet. You still need experience with server administration and networking to deploy your own server and fix any issues that may arise. You also need patience.
My experience with Coolify in this blog post was for the sake of experimentation and learning. But if I needed to deploy a production app, I would have just used Vercel. I don't want to encounter issues that could derail me from what really matters: shipping a product, getting feedback, and iterating.
I suggest you find out if you should self-host or use Vercel for hosting your Next.js app by answering the questions in this small tool.
Are you working in a team environment and your pull request process slows your team down? Then you have to grab a copy of my book, Pull Request Best Practices!