Docker standalone build inlining non NEXT_PUBLIC environment variables
Unanswered
Peterbald posted this in #help-forum
PeterbaldOP
I am trying to build a docker image, but next build keeps trying to read and even execute the code that uses the CONNECTION_STRING environment variable at build time.
I tried:
1. Placing it into another variable:
2. Throwing an error when the environment variable is not present:
if (!connectionString) {
throw new Error('Please add your Mongo connection string to .env.local');
}
3. Making a function that reads the variable:
const getEnvironmentVariable = (name: string): string => {
const value = process.env[name];
if (!value) {
throw new Error(
}
return value;
};
and a few other tricks, none of which helped. I am dumbstruck that even when I managed to get past the "environment variable missing", I got an error instantiating the MongoClient:
Another thing to note is, that, when I deleted all of my app/api/<some_route>/route.ts files, which were using the mongo client, then the error went away, while I'm still using the client in NextAuth:
`...
callbacks: {
async signIn({ user }) {
const client = await mongoClient;
const dbUser = await client
.db()
.collection<{ role: string }>('users')
.findOne({ email: user.email });
if (!dbUser) return false;
return true;
},
},
...
Note that my NextAuth is set up in the pages folder, not the app folder.
So now I am absolutely stumped as to why the build insists so much on inlining what quite obviously to me should not be inlined as is documented as though it will not be inlined here:
https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables
and is not used at all on the client side.
Help?
I tried:
1. Placing it into another variable:
const connectionString = process.env.CONNECTION_STRING;2. Throwing an error when the environment variable is not present:
if (!connectionString) {
throw new Error('Please add your Mongo connection string to .env.local');
}
3. Making a function that reads the variable:
const getEnvironmentVariable = (name: string): string => {
const value = process.env[name];
if (!value) {
throw new Error(
Missing environment variable: ${name});}
return value;
};
and a few other tricks, none of which helped. I am dumbstruck that even when I managed to get past the "environment variable missing", I got an error instantiating the MongoClient:
new MongoClient(connectionString!, options)Another thing to note is, that, when I deleted all of my app/api/<some_route>/route.ts files, which were using the mongo client, then the error went away, while I'm still using the client in NextAuth:
import mongoClient from '@/connectors/mongodb';`...
callbacks: {
async signIn({ user }) {
const client = await mongoClient;
const dbUser = await client
.db()
.collection<{ role: string }>('users')
.findOne({ email: user.email });
if (!dbUser) return false;
return true;
},
},
...
Note that my NextAuth is set up in the pages folder, not the app folder.
So now I am absolutely stumped as to why the build insists so much on inlining what quite obviously to me should not be inlined as is documented as though it will not be inlined here:
https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables
and is not used at all on the client side.
Help?

4 Replies
PeterbaldOP
I'd also like to note that I couldn't find a correct answer using Next documentation, Google search or any of the four available AI chatbots I have available, including the premium ChatGPT.
Another note: I'm basically using Next examples for a production
FROM node:alpine AS base
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
RUN mkdir .next
RUN chown nextjs:nodejs .next
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
ENV HOSTNAME "0.0.0.0"
CMD ["node", "server.js"]
And
import { MongoClient } from 'mongodb';
const options = {};
let client;
let clientPromise: Promise<MongoClient>;
const connectionString =
if (process.env.NODE_ENV === 'development') {
let globalWithMongo = global as typeof globalThis & {
_mongoClientPromise?: Promise<MongoClient>;
};
if (!globalWithMongo._mongoClientPromise) {
client = new MongoClient(connectionString, options);
globalWithMongo._mongoClientPromise = client.connect();
}
clientPromise = globalWithMongo._mongoClientPromise;
} else {
client = new MongoClient(connectionString, options);
clientPromise = client.connect();
}
export default clientPromise;
dockerfile:FROM node:alpine AS base
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
RUN mkdir .next
RUN chown nextjs:nodejs .next
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
ENV HOSTNAME "0.0.0.0"
CMD ["node", "server.js"]
And
mongoClient:import { MongoClient } from 'mongodb';
const options = {};
let client;
let clientPromise: Promise<MongoClient>;
const connectionString =
${process.env.CONNECTION_STRING}/${process.env.DATABASE_NAME}?retryWrites=true&w=majority;if (process.env.NODE_ENV === 'development') {
let globalWithMongo = global as typeof globalThis & {
_mongoClientPromise?: Promise<MongoClient>;
};
if (!globalWithMongo._mongoClientPromise) {
client = new MongoClient(connectionString, options);
globalWithMongo._mongoClientPromise = client.connect();
}
clientPromise = globalWithMongo._mongoClientPromise;
} else {
client = new MongoClient(connectionString, options);
clientPromise = client.connect();
}
export default clientPromise;
Transvaal lion
I'm facing the exact same issue. Using
All env params appear to be inlined regardless of the
output: 'standalone' , I cannot override server only env params from the docker run command. All env params appear to be inlined regardless of the
NEXT_PUBLIC prefix being present or not.Transvaal lion
OK, the issue I was having is different. I was able to get
process.env.GQL_URL to work and replace at runtime with docker run -e GQL_URL=test.com. The issue I was having is that next.js appears to inline params in next.config.js, even if they're NOT prefixed with NEXT_PUBLIC I was able to get it to work by utilizing middleware for the rewrite instead of the config setting.