I have a Mapbox map which I am trying to pass an environment variable in to using the built-in .env.local integration in NextJS 9.4. As per the Next docs, I am using a .env.local file and in order to expose the env variable to the browser, I am prefixing it with NEXT_PUBLIC_. However, the access token is not being passed through with this setup. When I pass the token in directly, it does work, so I know this is some sort of problem with the .env.local file not passing that particular env variable, even though it does with other tokens.
.env.local:
NEXT_PUBLIC_MAPBOX_TOKEN=my_mapbox_access_token
OTHER_API_TOKEN=my_other_api_token
map.js:
// Works
mapboxgl.accessToken = "my_mapbox_access_token";
// Doesn't work
mapboxgl.accessToken = process.env.NEXT_PUBLIC_MAPBOX_TOKEN;
other.js:
// Also works
class OtherAPI extends RESTDataSource {
constructor() {
super();
this.baseURL = "https://rest.otherapi.com/";
}
willSendRequest(request) {
request.headers.set(
"X-Application-Key",
process.env.OTHER_API_TOKEN
);
}...
So the Mapbox token works when it is passed directly, and the environment variables work when used with other APIs, but for some reason the env variables are not working with the Mapbox API. I've tried with and without the NEXT_PUBLIC_ prefix. What am I doing wrong?
Possibly this
You are using dotenv
Please see this discussion on GitHub:
https://github.com/vercel/next.js/discussions/12754
Related
I have a WebApp which fetches data from a database.
I have +server.js files from which my frontend fetches the data.
When I run npm run build:
adapter-auto:
No suitable adapter found.
adapter-static:
#sveltejs/adapter-static: all routes must be fully prerenderable, but found the following routes that are dynamic:
- src\routes
You have the following options:
- set the `fallback` option — see https://github.com/sveltejs/kit/tree/master/packages/adapter-static#spa-mode for more info.
- add `export const prerender = true` to your root `+layout.js/.ts` or `+layout.server.js/.ts` file. This will try to prerender all pages.
- add `export const prerender = true` to any `+server.js/ts` files that are not fetched by page `load` functions.
- pass `strict: false` to `adapter-static` to ignore this error. Only do this if you are sure you don't need the routes in question in your final app, as they will be unavailable. See https://github.com/sveltejs/kit/tree/master/packages/adapter-static#strict for more info.
If this doesn't help, you may need to use a different adapter. #sveltejs/adapter-static can only be used for sites that don't need a server for dynamic rendering, and can run on just a static file server.
See https://kit.svelte.dev/docs/page-options#prerender for more details
I experienced the same problem. What worked for me is adding export const prerender = true; to my +layout.server.ts file. In your case, just add it to your +server.js file at the top and run the build command again.
You can learn more about prerendering in SvelteKit docs
I'd like to load some environment variables into functions within my libs, and then be able to re-export this to several different Nextjs applications. i.e.
Within libs/api
export const getDatabaseConnection = () => {
const host = process.env.DB_HOST
const username = process.env.DB_USERNAME
...
return newDatabaseConnection
}
Within apps/myNextJSApp:
import { getDatabaseConnection } from '#myProject/api'
...
const databaseConnection = getDatabaseConnection()
...
When I run nx run myNextJSApp:serve it's unable to pull the environment variables from the .env within the root directory, however if I run nx run api:test it's completely happy. I think I could pull the environment variables from each app individually, and then pass them as params into my library functions, but this seems kind of tedious, and I was hoping theres a blanket solution to this where I could build my library modules with the environment variables, and export them to my NextJS apps.
Environment variables don't suppose to share by multiple apps. And it's better that you don't do it either. Every app you're creating should have its environment file. And don't read the environment from your libs directly. You must load the environment variable in your app and pass it to the lib.
For example, pass the needed config to the libs function:
// libs/api
export const getDatabaseConnection = ({host, username}) => {
const host = host
const username = usename
...
return newDatabaseConnection
}
// apps/nextjs
import { getDatabaseConnection } from '#myProject/api'
...
const databaseConnection = getDatabaseConnection({
host: process.env.DB_HOST,
username: process.env.DB_USERNAME
})
This way, your code is more reusable and maintainable.
And as I said, don't ever share your environment variables between apps.
I am trying to make a POC and I'm such making a really simple use-case.
In there, I use a src/lib/db.ts who, for our interest, contains this code
console.log(import.meta.env.MONGO_URI, import.meta.env.SSR);
giving
undefined true
Of course, my .env file contains a definition for MONGO_URI, I tried with VITE_MONGO_URI and could see the value.
I know a way to expose it is to use VITE_MONGO_URI but my point is exactly not to expose it on the client-side.
I checked and the file db.ts is not bundled with the client, even the import.meta.env.SSR being true shows that the bundler knows it's happening on the server.
Question: How to access my private environment variables server-side ?
EDIT: As specified by Shriji Kondan, the API for this purpose has been created now : here
You could use dotenv on the server side, assuming you are using node-adapter, you can have a file _constants.ts in your app
import 'dotenv/config';
export const MONGO_URI = process.env.MONGO_URI;
and then import this variable into your script.
It's not very awesome to put secrets on client-side code. It should be either utilities.ts with a performed action SUPER_SECRET_API_KEY="$ecret#p1Key" in .env file, then request it via in src/lib/utilities/utility.js as explained here :
import { SUPER_SECRET_API_KEY } from '$env/static/private';
export function performApiAction() {
const apiInstance = initialiseApi({key: SUPER_SECRET_API_KEY});
}
or from page.server.ts via form actions as stated here which is preferable way but it's more complex.
I need to pass a configuration value from one CDK stack to another and use that value in the second stack's construct code bundling step. E.g. first stack is S3 bucket and the second stack is Lambda#Edge function which doesn't support environment variables and needs to embed S3 bucket name in code during bundling in a custom construct. When I do this I get values like ${Token[TOKEN.214]} instead of a real bucket name.
let bucket: Bucket
// This function builds and bundles the code for Lambda#Edge
buildLambdaCode(..., { env: { S3_BUCKET: bucket.bucketName } })
Indeed, CDK-generated resource names are Tokens at code-time, CloudFormation Refs at synth-time, and "actual names" only at deploy-time. So your options to pass the bucket name to your Lambda#Edge are:
Environment Variable: the default solution, but Lambda#Edge does not support them*, as you say.
SSM Parameter + SDK Call: another typical solution, but the added latency defeats the purpose of the edge function.
CloudFront Custom Header: as in this SO Question. You can set customHeaders in CDK Cloudfront Origin constructs.
Hardcode the Bucket Name: the best-practice gods may forgive you setting an explicit bucketName in this case.
* The experimental cloudfront.experimental.EdgeFunction construct dangerously permits env var props (error or ignored at deploy?). The stable cloudfront.Function does not, in line with the service docs.
I am currently working on a grails application. Previously I have been using Django alot to create webapps. In django you can easily create settings that are collected from the OS environment. I find that to be an easy solution for making sure that you don't check in usernames and passwords into the source code repository.
So what I would like to do is in the DataSource.groovy be able to lift in the username and password from the OS environment. Has anyone done anything like this, or is this not the way to go forward?
If this is not the "grails way", how is it supposed to be done, because having the username and password in the repository just feels wrong?
You can write code in DataSource.groovy and Config.groovy to get env variable and then set username password and other things. I always to it for my production app, sample code is as follows
//Eample is based on url structure like "mysql://username:password#host/database?autoReconnect=true&useUnicode=yes&characterEncoding=UTF-8"
dataSource {
String mysqlUrl = System.getenv("DATABASE_URL")
println ">>>>>> Got DATABASE_URL: ${mysqlUrl} <<<<<<<"
URI dbUri = new URI(mysqlUrl);
username = dbUri.userInfo.split(":")[0]
password = dbUri.userInfo.split(":")[1]
String databaseUrl = "jdbc:${dbUri.scheme}://${dbUri.host}${dbUri.path}"
if (dbUri.port > 0) {
databaseUrl += ":${dbUri.port}"
}
String query = dbUri.query ?: "reconnect=true"
query += "&autoReconnect=true&useUnicode=yes&characterEncoding=UTF-8"
databaseUrl += "?${query}"
url = databaseUrl
dialect = 'org.hibernate.dialect.MySQL5InnoDBDialect'
}
This is one of the way I am sure there must be some simpler way to do this.
PS: I find it simple though :)
You can create a environment variable in Windows. Example DBCONNGRAILS. In config.groovy (...\grails-app\conf\config.groovy) you can use something like
def myConnectionString = System.getenv(DBCONNGRAILS)
WARNING: If you get variables from the environment(Windows) there will no problem when loading the value when in development. But when you are working with a production server, there will be cases when you will need to resart the OS for tomcat to be able to pick up the changes. I would recommend externalizing the config files.
You can externalized the configuration in any other place and load/merge it simply in your application configuration.
We use JNDI at work for exactly this scenario. We have context.xml files located within the individual server's Tomcat directories. The context.xml contains the datasource properties and then within the datasource closure (defined in Datasource.groovy), the jndiName property is set accordingly.
More Links about JNDI:
http://grails.github.io/grails-doc/2.3.7/guide/conf.html#JNDIDataSources
http://grails.asia/how-to-make-grails-use-jndi-datasource-with-tomcat