How to handle sensitive environment variable?
Answered
Masai Lion posted this in #help-forum
Masai LionOP
// file that establishes a database connection
connection(process.env.DB_CONNECTION)
// api/user/route that uses the database connection
import db from './database-connection'I'm having issues creating a production build using a docker image that will be deployed on kubernetes. I normally attach environment variables in a deployment file but it seems like nextjs expects these variables to be available at build time. So it seems like I have to put my db credentials inside a .env file. Is this correct or can I still make use of k8 secrets and defer the running of the actual code for when the app is actually deployed? I'm using Next v14.2.3.
Answered by Masai Lion
I think I'm going to have to go with wrapping my db initializing code in a function and move it inside the route handler, because if I just give it a dummy value the initializing code still tries to run and and that throws an error which also fails the build...
24 Replies
@Masai Lion
// file that establishes a database connection
connection(process.env.DB_CONNECTION)
// api/user/route that uses the database connection
import db from './database-connection'
I'm having issues creating a production build using a docker image that will be deployed on kubernetes. I normally attach environment variables in a deployment file but it seems like nextjs expects these variables to be available at build time. So it seems like I have to put my db credentials inside a .env file. Is this correct or can I still make use of k8 secrets and defer the running of the actual code for when the app is actually deployed? I'm using Next v14.2.3.
NEXT_PUBLIC_* env vars must be available at build time. Server side secrets (like DB_CONNECTION above) need not be available at build time.Masai LionOP
Under want scenarios would DB_CONNECTION need to be available at build time because
next build will fail for me if it's not there.@Masai Lion Under want scenarios would DB_CONNECTION need to be available at build time because `next build` will fail for me if it's not there.
When it’s needed to run something that is executed at build time, for example a static page or a static route handler
To make the route/page dynamic instead of static, add
export const revalidate = 0 to itMasai LionOP
would this apply to api routes as well? from the stack trace it looks like the
app/api route is the entry pointAPI routes in the app router are called route handlers
Masai LionOP
I tried adding it to api/user/route.ts file but still running into this issue. Since the problem is in
app/api/user/route.ts (route handler) does this mean that the build is encountering code inside of app/*/page.tsx that is referencing app/api/user/route.ts?Anything static inside your app cannot depend on the env variable because those things are run at build time. So go check see what pages/routes are static in your app and whether those pages/routes depend on the env var
I can’t really say more than this considering the amount of information available here
Masai LionOP
could you tell me what would make app/api/user/route.ts static? I'm trying to understand why the build is running any code in a route handler
GET routes that do not depend on the request object are automatically statically rendered at build time by default (this will change in Next.js v15)
Masai LionOP
Thanks. Is it true that I need to move db initializing code into the route hander?
vs
export async function POST(req: NextRequest) {
const db = initialize_db()
}vs
import db from './database_connection'
export async function POST(req: NextRequest) {
const db.makecalls()
}POST handlers are never static. Could you make a reproduction repository?
Masai LionOP
Yup, I can try
Masai LionOP
here's a repo that reproduces the issue I'm seeing https://github.com/M-beep854/nextjs-repro
All I did was add one route handler and a configuration file
import db from '@/app/config/database_connection';
import { NextRequest, NextResponse } from 'next/server';
export async function POST(req: NextRequest) {
try {
return NextResponse.json({ test: db });
} catch (error) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
}const test = process.env.TESTING!.replace('t', ' ');
console.log(test);
export default test;@Masai Lion All I did was add one route handler and a configuration file
import db from '@/app/config/database_connection';
import { NextRequest, NextResponse } from 'next/server';
export async function POST(req: NextRequest) {
try {
return NextResponse.json({ test: db });
} catch (error) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
}
const test = process.env.TESTING!.replace('t', ' ');
console.log(test);
export default test;
console.log("This is still run at build time so cant access the env var here")
export async function POST(req) {
console.log("This is not run at build time so can access the env var here")
// ...
}that's why it throws an error. just give the env var a dummy value at build time then change it during runtime
Masai LionOP
I think I'm going to have to go with wrapping my db initializing code in a function and move it inside the route handler, because if I just give it a dummy value the initializing code still tries to run and and that throws an error which also fails the build...
Answer
actually nvm, yeah that sounds like a good choice
Masai LionOP
I'm guessing there's a reason for why it's done this way, would be nice if I didn't have to do this work around though... Thanks for the help!
Asian black bear
I wanted to chime in real quick and mention I haven't read the conversation up to this point but I can guess what joulev has mentioned. For elaborate runtime based variables when using k8s you might want to check out this: https://github.com/expatfile/next-runtime-env
Unlike the normal approach of Next to bake variables into the artifact you can access them dynamically which makes it much easier with service location and other techniques in the context of k8s.
Seeing your initial example of a server-side connection string, this won't help, but it might come in handy eventually for dynamic public variables
Masai LionOP
Thanks Near, I'll check it out!