Can't find DATABASE_URL during deployment

I’m deploying a Next.js + Postgres/Prism app and it fails because it can’t find the DATABASE_URL.

The error during deployment happens when it tries to run npx prisma migrate deploy from the Dockerfile:

#12 3.531 error: Environment variable not found: DATABASE_URL.                                                                                                                   
#12 3.531   -->  schema.prisma:10
#12 3.531    | 
#12 3.531  9 |     provider = "postgresql"
#12 3.531 10 |     url      = env("DATABASE_URL")

The DATABASE_URL is set in the secrets for the Next.js app:

$ fly secrets list
NAME            DIGEST                  CREATED AT 
DATABASE_URL    <digest>                9m40s ago 

I verify it by typing this:

$ fly ssh console
Connecting to servername.internal... complete
# echo $DATABASE_URL
postgres://...

The Dockerfile is the default one that Fly generated, but I added these two lines:

RUN npx prisma migrate deploy
RUN npx prisma generate

The fly.toml file is the default, generated one, except I changed the port from 8080 to 3000.

The deployment does work if I hard-code the DATABASE_URL in the Dockerfile like this, but I don’t want to store the password in Git:

ENV DATABASE_URL postgres:://...

RUN npx prisma migrate deploy
RUN npx prisma generate

I tried deleting the Next app and Postgres database from Fly and recreating them, but the problem still exists on the new version.

Edit: I also tried adding the DATABASE_URL as a secret to the builder app, but it failed there too.

Does anyone know why it isn’t working?

The app needs a build-time var, whereas fly secrets are only available at runtime which is after your app is up and running inside a Fly-managed VM (this is why printenv DATABASE_URL works in that ssh session).

Try supplying Dockerfile those vars via --build-arg switch to fly deploy (ref). You can then assign these ARGs to ENVs in the Dockerfile. As a bonus, env vars set with the ENV directive are also available to the VM at runtime (unless overriden by values from fly secrets, so make sure to unset if there are conflicting keys).

Thanks, that worked. It it safe for database passwords?

If access to the database server is restricted (say over a tightly-controlled network and ACLs), then I guess it is okay to expose password like that… but if I were you, I’d not do it.

I’m confused. Is there no safe way to manage database passwords on build images?

Yes, with build-time secrets (if runtime secrets aren’t sufficient): RAILS_MASTER_KEY environment variable not getting fetched - #2 by ignoramous

This is the way. The syntax is a bit cumbersome if you have a bunch of secrets (I do because I am not yet using the relatively new Rails approach to secrets) … but it worked for me to get a Rails app deploying before I learned I could move the asset compilation step out of the build step to circumvent this issue.