I’ve been trying for a few hours to deploy my Next.js / prisma application.
With the generated Dockerfile and fly.toml The build deployment was successful, however my database is not properly connected to my web application.
I created a separate fly postgres database and connected the two with flyctl postgres attach. Attachment was successful, but I still got an error on my application.
I tried first creating the database and then deploy the Next.js application, with no success.
From my research, it seems Next.js requires the DATABASE_URL env variable at build time.
I tried a few things, such as hard coding the DATABASE_URL value in my Dockerfile, fly.io build secrets tutorial, none of which have worked.
Either I get a strange error regarding TLS at build time when I added RUN npx prisma migrate deploy interrupting the deployment, or an issue with locating my database once the application is correctly deployed and running.
The guides on fly.io, prisma or Next.js did not help me fixing the problem.
My questions are the following:
How do I properly set the DATABASE_URL variable at build time?
Docker was giving me an error because of cat when following fly.io “Build Secrets” tutorial. Hard coding seems to at least deploy the app but this is unsafe.
Do I need to add anything else for prisma beside the default RUN npx prisma generate?
I can’t find any information regarding this on prisma deployment. I don’t think my database is properly created.
# syntax = docker/dockerfile:1
# Adjust NODE_VERSION as desired
ARG NODE_VERSION=19.8.1
FROM node:${NODE_VERSION}-slim as base
LABEL fly_launch_runtime="Next.js/Prisma"
# Next.js/Prisma app lives here
WORKDIR /app
# Set production environment
ENV NODE_ENV="production"
# Throw-away build stage to reduce size of final image
FROM base as build
# Install packages needed to build node modules
RUN apt-get update -qq && \
apt-get install -y build-essential openssl pkg-config python-is-python3
# Install node modules
COPY --link package-lock.json package.json ./
RUN npm ci --include=dev
# Generate Prisma Client
COPY --link prisma .
RUN --mount=type=secret,id=DATABASE_URL \
DATABASE_URL="$(cat /run/secrets/DATABASE_URL)" npx prisma generate
# Copy application code
COPY --link . .
# Build application
RUN npm run build
# Remove development dependencies
RUN npm prune --omit=dev
# Final stage for app image
FROM base
# Install packages needed for deployment
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y openssl && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Copy built application
COPY --from=build /app /app
# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD [ "npm", "run", "start" ]
My fly.toml config file is unchanged.
I deploy my app. flyctl deploy --build-secret DATABASE_URL=postgres://<username>:<password>@pg-<app-name>.flycast:5432 with the actual db username, password and db app name.
[...]
This deployment will:
* create 2 "app" machines
No machines in group app, launching a new machine
Machine <number> [app] update finished: success
Creating a second machine to increase service availability
Machine <number> [app] update finished: success
Finished launching new machines
NOTE: The machines for [app] have services with 'auto_stop_machines = true' that will be stopped when idling
My Next.js app is now online, accessible at the deployed link.
I set the DATABASE_URL secret since it was not set.
I did so with fly secrets set DATABASE_URL=<db-connection-string>, identical one used for deploying.
When I access my application, I get an error message when I want to say create a new user.
This is the error message when I want to do anything involving the database:
Invalid `prisma.survey.findUnique()` invocation: Error opening a TLS connection: unexpected EOF
Can I see your schema.prisma file? By any chance does it define sslmode? This needs to be either disable or prefer as the postgres db is not running with ssl/tls.
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(uuid())
email String @unique
hash String
salt String
createdAt DateTime @default(now()) @map(name: "created_at")
updatedAt DateTime @updatedAt @map(name: "updated_at")
admin Boolean @default(false)
surveys Survey[]
@@map(name: "users")
}
[ all my other models... ]
I don’t have much experience with next.js (perhaps others can chime in here?), but if you have postgres installed locally and can set DATABASE_URL, if you run the following in an empty directory you will get a minimal prisma/postgres application that you can deploy:
Thank you for your reply. I will try deploying this example see if it works.
Could this be due to something related to server certificate?
Prisma has a setting to accept self signed certificates with postgres. Is this possibly the case here?
should I accept self signed certificate with sslaccept=accept_invalid_certs?
Edit: accept_invalid_certs is supposedly already the default. But maybe append it to the DATABASE_URL in some way?
How can I manually test and see if the database and the server can communicate together?
Edit 2: I connected to my database with fly pg connect -a pg-<app-name>. I do not see my app database, only postgres, pgmr, template0 and template1.
I believe this may be causing the issue.
With fly postgres, you want no certs, valid or invalid. The database is running on a private network and is not accessible to the internet so none of this is necessary.
The piece I don’t understand is what in your configuration is telling prisma to use ssl/tls; if you can figure that out, you will need to turn that off.
I disabled SSL and added a database name for the deployment, thinking this was maybe the issue. flyctl deploy --build-secret DATABASE_URL="postgres://<username>:<password>@pg-<app-name>.flycast:5432/<db>?schema=public&sslmode=disable"
This didn’t change the result, I still get the TLS error. The app does deploy however.
I decided to try modifying my Dockerfile, see if that was the issue. In my Dockerfile, I added npx prisma migrate deploy like this:
I also came across this link. The shell script run at the end of the dockerfile actually contains npx prisma migrate deploy.
I was able to deploy my app using a hard-coded ENV DATABASE_URL. Here is the Dockerfile:
# syntax = docker/dockerfile:1
# Adjust NODE_VERSION as desired
ARG NODE_VERSION=19.8.1
FROM node:${NODE_VERSION}-slim as base
LABEL fly_launch_runtime="Next.js/Prisma"
# Next.js/Prisma app lives here
WORKDIR /app
# Set production environment
ENV NODE_ENV="production"
ENV DATABASE_URL="postgres://<username>:<password>@pg-<app-name>.flycast:5432/<db>?schema=public&sslmode=disable"
# Throw-away build stage to reduce size of final image
FROM base as build
# Install packages needed to build node modules
RUN apt-get update -qq && \
apt-get install -y build-essential openssl pkg-config python-is-python3
# Install node modules
COPY --link package-lock.json package.json ./
RUN npm ci --include=dev
# Generate Prisma Client
COPY --link prisma .
RUN npx prisma generate
# Copy application code
COPY --link . .
# Build application
RUN npm run build
RUN npx prisma migrate deploy
RUN npx prisma db seed
# Remove development dependencies
RUN npm prune --omit=dev
# Final stage for app image
FROM base
# Install packages needed for deployment
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y openssl && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Copy built application
COPY --from=build /app /app
# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD [ "npm", "run", "start" ]
prisma migrate deploy is used after the run build.
It may work if used before building as well, but I decided to follow what remix did with their Dockerfile.
It’s working for now. However if you know how to not hard-code the DATABASE_URL in my Dockerfile that would be great.
Admittedly this hardcodes the secret in a different place (presumably a script on your development machine), but you can commit your Dockerfile and add that script to your .gitignore and .dockerignore files.