docs/framework/quickstart/nestjs.mdx
In this guide, we will add a Novu Bridge Endpoint to a NestJS application and send our first test workflow.
<Steps> <Step> ### Set up your local environmentStart the Local Studio by running:
npx novu dev
The Local Studio will be available at http://localhost:2022. This is where you can preview and test your workflows.
</Step>
Install the Novu Framework package:
npm install @novu/framework
This package provides all the necessary tools to build and manage your notification workflows.
</Step>
<Step title="Add the NovuModule to your application">
The `NovuModule` is a NestJS module that registers the Novu Endpoint in your application.
The following example does not support NestJS dependency injection. If you need to `@Injectable` dependencies in your workflow definition, see [Advanced Usage](#advanced-usage-dependency-injection).
```typescript src/app.module.ts
@Module({
imports: [
NovuModule.register({
apiPath: '/api/novu',
workflows: [testWorkflow],
}),
],
})
export class AppModule {}
```
</Step>
<Step>
### Configure your secret key
Add your Novu secret key to your environment variables:
NOVU_SECRET_KEY=your_secret_key
</Step>
<Step>
### Create your workflow definition
Add a `novu` folder in your `src` folder as such ```src/novu/workflows.ts``` that will contain your workflow definitions.
import { workflow } from '@novu/framework';
export const testWorkflow = workflow('test-workflow', async ({ step }) => {
await step.email('test-email', async () => {
return {
subject: 'Test Email',
body: 'This is a test email from Novu Framework!',
};
});
});
</Step>
<Step>
### Start your application
Start your NestJS application with the Novu Endpoint configured.
If your NestJS application is running on other than `4000` port, restart the `npx novu dev` command with the port:
```tsx
npx novu@latest dev --port <YOUR_NESTJS_APPLICATION_PORT>
```
</Step>
<Step>
### Test your endpoint
Test your workflow by triggering it from the Local Studio or using the Novu API:
curl -X POST https://api.novu.co/v1/events/trigger \
-H 'Authorization: ApiKey YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"name": "my-workflow",
"to": "subscriber-id",
"payload": {}
}'
You should see the notification being processed in your Local Studio.
</Step>
<Step>
### Deploy your application
Deploy your application to your preferred hosting provider. Make sure the /api/novu endpoint is accessible from the internet.
For local development and testing, you can use tools like ngrok to expose your local server to the internet.
</Step>
Now that you have your first workflow running, you can:
If you need to inject dependencies into your workflow definition, you can use the registerAsync method.
Add the NovuModule using the registerAsync method to your AppModule.
import { Module } from '@nestjs/common';
import { NovuModule } from '@novu/framework/nest';
import { NotificationService } from './notification.service';
import { UserService } from './user.service';
@Module({
imports: [
NovuModule.registerAsync({
imports: [AppModule],
useFactory: (notificationService: NotificationService) => ({
apiPath: '/api/novu',
workflows: [notificationService.welcomeWorkflow()],
}),
inject: [NotificationService],
}),
],
providers: [NotificationService, UserService],
exports: [NotificationService],
})
export class AppModule {}
For example, you might need to inject a service that fetches the user's name from a database. This is useful when you need to fetch data in realtime during the execution of your workflow.
An example UserService is available below with hardcoded values, but in a real-world application you might use a database or an external API to fetch the user's name.
import { Injectable } from '@nestjs/common';
@Injectable()
export class UserService {
getUser(id: string) {
return {
name: 'John Doe',
email: `john.doe.${id}@example.com`,
};
}
}
Finally, configure your NotificationService to use the injected UserService.
import { Injectable } from '@nestjs/common';
import { workflow } from '@novu/framework';
import { z } from 'zod';
import { UserService } from './user.service';
@Injectable()
export class NotificationService {
constructor(private readonly userService: UserService) {}
public welcomeWorkflow() {
return workflow(
'welcome-email',
async ({ step, payload }) => {
await step.email('send-email', async () => {
const user = this.userService.getUser(payload.userId);
return {
subject: `Hello, ${user.name}`,
body: `We are glad you are here!`,
};
});
},
{
payloadSchema: z.object({
userId: z.string(),
}),
}
);
}
}
A full example NestJS application demonstrating dependency injection is available here.