Xata issues with environment variables in NestJS

I have a simple NestJS app, generated through their cli, and have attempted to add Xata to the project to use as my database. I've ran the xata init command, and everything generated correctly and my environment variables were added to my .env file. However, where I try to run my app with pnpm start:dev (a precreated script) I get this error:
E:\***\node_modules\.pnpm\@xata.io+client@0.29.5_typescript@5.4.5\node_modules\@xata.io\client\src\client.ts:108
throw new Error('Option apiKey is required');
^
Error: Option apiKey is required
at XataClient.parseOptions_fn (E:\***\node_modules\.pnpm\@xata.io+client@0.29.5_typescript@5.4.5\node_modules\@xata.io\client\src\client.ts:108:15)
at new _a (E:\***\node_modules\.pnpm\@xata.io+client@0.29.5_typescript@5.4.5\node_modules\@xata.io\client\src\client.ts:47:27)
at new XataClient (E:\***\src\lib\xata.ts:80:5)
at getXataClient (E:\***\src\lib\xata.ts:89:14)
at KeyCache.init (E:\***\remorse\nest-backend\src\lib\KeyCache.ts:12:40)
at new KeyCache (E:\***\src\lib\KeyCache.ts:8:10)
at Object.<anonymous> (E:\***\src\lib\KeyCache.ts:39:16)
at Module._compile (node:internal/modules/cjs/loader:1378:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1437:10)
at Module.load (node:internal/modules/cjs/loader:1212:32)
E:\***\node_modules\.pnpm\@xata.io+client@0.29.5_typescript@5.4.5\node_modules\@xata.io\client\src\client.ts:108
throw new Error('Option apiKey is required');
^
Error: Option apiKey is required
at XataClient.parseOptions_fn (E:\***\node_modules\.pnpm\@xata.io+client@0.29.5_typescript@5.4.5\node_modules\@xata.io\client\src\client.ts:108:15)
at new _a (E:\***\node_modules\.pnpm\@xata.io+client@0.29.5_typescript@5.4.5\node_modules\@xata.io\client\src\client.ts:47:27)
at new XataClient (E:\***\src\lib\xata.ts:80:5)
at getXataClient (E:\***\src\lib\xata.ts:89:14)
at KeyCache.init (E:\***\remorse\nest-backend\src\lib\KeyCache.ts:12:40)
at new KeyCache (E:\***\src\lib\KeyCache.ts:8:10)
at Object.<anonymous> (E:\***\src\lib\KeyCache.ts:39:16)
at Module._compile (node:internal/modules/cjs/loader:1378:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1437:10)
at Module.load (node:internal/modules/cjs/loader:1212:32)
This is my KeyCache.ts file:
import { getXataClient } from './Xata';

class KeyCache {
cache: Set<string>;

constructor() {
this.cache = new Set<string>();
this.init();
}

async init() {
const records = await getXataClient().db.uploads.select(['slug']).getAll();
records.forEach((rec) => {
if (rec && typeof rec.slug === 'string') {
this.cache.add(rec.slug);
}
});
}

getUniqueId(length: number) {
let string = this.generateRandomString(length);
while (this.cache.has(string)) string = this.generateRandomString(length);
this.cache.add(string);
return string;
}

private generateRandomString(length: number) {
let result = '';
const characters =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < length; i++)
result += characters.charAt(
Math.floor(Math.random() * characters.length),
);
return result;
}
}

export default new KeyCache();
import { getXataClient } from './Xata';

class KeyCache {
cache: Set<string>;

constructor() {
this.cache = new Set<string>();
this.init();
}

async init() {
const records = await getXataClient().db.uploads.select(['slug']).getAll();
records.forEach((rec) => {
if (rec && typeof rec.slug === 'string') {
this.cache.add(rec.slug);
}
});
}

getUniqueId(length: number) {
let string = this.generateRandomString(length);
while (this.cache.has(string)) string = this.generateRandomString(length);
this.cache.add(string);
return string;
}

private generateRandomString(length: number) {
let result = '';
const characters =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < length; i++)
result += characters.charAt(
Math.floor(Math.random() * characters.length),
);
return result;
}
}

export default new KeyCache();
My environment variables are working fine as in the root file (main.ts) I have the following code:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
console.log(process.env.XATA_API_KEY);
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());
await app.listen(3000);
}
bootstrap();
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
console.log(process.env.XATA_API_KEY);
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());
await app.listen(3000);
}
bootstrap();
and the appropriate variable is outputted near the start of the logs (before the errors). Does anyone know what might be causing this error? Could it be the way in which files are loaded in NestJS, meaning that the KeyCache file that requires xata be loaded before environment variables are set/available to the app? Thanks in advance :)
3 Replies
kostas
kostas3mo ago
Hi, indeed it looks like the Xata client cannot get the API key env variable during instantiation. Maybe it has to do with the Config Module? https://docs.nestjs.com/techniques/configuration#getting-started To work around this you can try importing the XataClient and pass the key and other parameters to it explicitly: https://xata.io/docs/sdk/typescript/overview#manually-passing-the-apikey We've found this approach necessary for other frameworks as well such as SvelteKit, which has a particular way of using env variables (see the XataClient config in this example https://xata.io/docs/getting-started/sveltekit#query-and-list-the-posts)
PeanutDumplings
PeanutDumplings3mo ago
This didn't seem to work In my app.module.ts file, as per the docs, I checked that my code matched the doc's code (which is did)
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ImageModule } from './image/image.module';
import { ConfigModule } from '@nestjs/config';

@Module({
controllers: [AppController],
providers: [AppService],
imports: [ConfigModule.forRoot(), ImageModule],
})
export class AppModule {}
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ImageModule } from './image/image.module';
import { ConfigModule } from '@nestjs/config';

@Module({
controllers: [AppController],
providers: [AppService],
imports: [ConfigModule.forRoot(), ImageModule],
})
export class AppModule {}
as well as manually passing the api key, changing this
async init() {
const records = await getXataClient().db.uploads.select(['slug']).getAll();
records.forEach((rec) => {
if (rec && typeof rec.slug === 'string') {
this.cache.add(rec.slug);
}
});
}
async init() {
const records = await getXataClient().db.uploads.select(['slug']).getAll();
records.forEach((rec) => {
if (rec && typeof rec.slug === 'string') {
this.cache.add(rec.slug);
}
});
}
to this
async init() {
const xata = new XataClient({ apiKey: process.env.XATA_API_KEY });
const records = await xata.db.uploads.select(['slug']).getAll();
records.forEach((rec) => {
if (rec && typeof rec.slug === 'string') {
this.cache.add(rec.slug);
}
});
}
async init() {
const xata = new XataClient({ apiKey: process.env.XATA_API_KEY });
const records = await xata.db.uploads.select(['slug']).getAll();
records.forEach((rec) => {
if (rec && typeof rec.slug === 'string') {
this.cache.add(rec.slug);
}
});
}
I'm still confused how this error is even occuring at that point, because chronologically in the logs it goes:
[1:25:01 pm] Starting compilation in watch mode...

[1:25:04 pm] Found 0 errors. Watching for file changes.

xau_****** (api key)
[Nest] 2484 - 02/07/2024, 1:25:04 pm LOG [NestFactory] Starting Nest application...
[Nest] 2484 - 02/07/2024, 1:25:04 pm LOG [InstanceLoader] ConfigHostModule dependencies initialized +7ms
[Nest] 2484 - 02/07/2024, 1:25:04 pm LOG [InstanceLoader] AppModule dependencies initialized +0ms
[Nest] 2484 - 02/07/2024, 1:25:04 pm LOG [InstanceLoader] ConfigModule dependencies initialized +1ms
[Nest] 2484 - 02/07/2024, 1:25:04 pm LOG [InstanceLoader] ImageModule dependencies initialized +0ms
[Nest] 2484 - 02/07/2024, 1:25:05 pm LOG [RoutesResolver] AppController {/}: +124ms
[Nest] 2484 - 02/07/2024, 1:25:05 pm LOG [RouterExplorer] Mapped {/, GET} route +1ms
[Nest] 2484 - 02/07/2024, 1:25:05 pm LOG [RoutesResolver] ImageController {/image}: +0ms
[Nest] 2484 - 02/07/2024, 1:25:05 pm LOG [RouterExplorer] Mapped {/image/:id, GET} route +0ms
[Nest] 2484 - 02/07/2024, 1:25:05 pm LOG [RouterExplorer] Mapped {/image, POST} route +1ms
[Nest] 2484 - 02/07/2024, 1:25:05 pm LOG [RouterExplorer] Mapped {/image, DELETE} route +0ms
[Nest] 2484 - 02/07/2024, 1:25:05 pm LOG [NestApplication] Nest application successfully started +1ms

xata api key error, same as in original post
[1:25:01 pm] Starting compilation in watch mode...

[1:25:04 pm] Found 0 errors. Watching for file changes.

xau_****** (api key)
[Nest] 2484 - 02/07/2024, 1:25:04 pm LOG [NestFactory] Starting Nest application...
[Nest] 2484 - 02/07/2024, 1:25:04 pm LOG [InstanceLoader] ConfigHostModule dependencies initialized +7ms
[Nest] 2484 - 02/07/2024, 1:25:04 pm LOG [InstanceLoader] AppModule dependencies initialized +0ms
[Nest] 2484 - 02/07/2024, 1:25:04 pm LOG [InstanceLoader] ConfigModule dependencies initialized +1ms
[Nest] 2484 - 02/07/2024, 1:25:04 pm LOG [InstanceLoader] ImageModule dependencies initialized +0ms
[Nest] 2484 - 02/07/2024, 1:25:05 pm LOG [RoutesResolver] AppController {/}: +124ms
[Nest] 2484 - 02/07/2024, 1:25:05 pm LOG [RouterExplorer] Mapped {/, GET} route +1ms
[Nest] 2484 - 02/07/2024, 1:25:05 pm LOG [RoutesResolver] ImageController {/image}: +0ms
[Nest] 2484 - 02/07/2024, 1:25:05 pm LOG [RouterExplorer] Mapped {/image/:id, GET} route +0ms
[Nest] 2484 - 02/07/2024, 1:25:05 pm LOG [RouterExplorer] Mapped {/image, POST} route +1ms
[Nest] 2484 - 02/07/2024, 1:25:05 pm LOG [RouterExplorer] Mapped {/image, DELETE} route +0ms
[Nest] 2484 - 02/07/2024, 1:25:05 pm LOG [NestApplication] Nest application successfully started +1ms

xata api key error, same as in original post
kostas
kostas3mo ago
I tried the sample nestJS app https://docs.nestjs.com/#installation and set it to read from Xata with no issues. I made changes to app.service.ts and app.controller.ts to return Promise. The Xata client picks up the Xata API key from .env and returns query results. see the recording. Can you try the same on the sample nestJS app and see if that works for you? I suspect some caching or build issue, maybe try on a fresh project?
Documentation | NestJS - A progressive Node.js framework
Documentation | NestJS - A progressive Node.js framework
Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).
Want results from more Discord servers?
Add your server