Nest.js and React are two powerful technologies that have gained significant traction among developers for creating modern web applications. Nest.js is a framework for building efficient server-side applications, while React is renowned for its capabilities in building user interfaces for single-page applications. Together, they form a full stack that can handle both frontend and backend development seamlessly.
When combined, Nest.js and React allow developers to create scalable, maintainable, and high-performance web apps. This blog post will explore how these two technologies can be used together to build a new project that leverages the strengths of both.
We'll delve into the installation process, project structure, and how to create a react app that communicates with a Nest.js backend.
Yes, Nest.js can be used with React to develop scalable web apps. Nest.js serves as the server-side framework, handling API requests, business logic, and database interactions, while React takes care of the frontend, providing a dynamic and responsive user interface.
1// Example of a simple Nest.js controller 2import { Controller, Get } from '@nestjs/common'; 3 4@Controller('api') 5export class AppController { 6 @Get('data') 7 getData() { 8 return { message: 'Data fetched successfully' }; 9 } 10}
To set up a new project with both Nest.js and React, you'll need to create two separate parts of the same project: the backend directory for Nest.js and the frontend app for React. Using a package manager like npm or yarn, you can initialize a new NestJS project and a React application in the root directory of your project.
1# Initialize a new Nest.js project 2nest new backend 3 4# Initialize a new React app 5npx create-react-app frontend
As of 2024, Nest.js continues to be a valuable tool for developers. Its architecture is heavily inspired by Angular, offering a consistent and modular way to organize code through the use of controllers, services, and modules. This makes it an excellent choice for building scalable server-side applications.
Nest.js's use of TypeScript (ts file), dependency injection, and design patterns like MVC, make it a robust framework for server-side development. It's compatible with various databases and supports both REST and GraphQL APIs, making it a versatile choice for any project.
Nest.js is a backend framework. It is designed to run on the server side, handling HTTP requests, implementing business logic, interacting with databases, and managing user authentication and authorization.
While Nest.js takes care of the server-side logic, it can be paired with frontend frameworks like React to handle the view layer. This separation of concerns allows developers to focus on specific areas of the application without overlap.
React is a popular choice to pair with Nest.js due to its component-based architecture and efficient update system. It allows for the creation of interactive user interfaces that can easily communicate with a Nest.js backend through API calls.
React's ecosystem, including tools like Redux for state management and React Router for navigation, complements Nest.js's scalable architecture. This combination is ideal for developers looking to create full stack applications that are both powerful and user-friendly.
To combine React and Nest.js in a new project, you can use the create-react-app CLI tool to scaffold a new React application. In the same project, you can use the Nest CLI to generate a new Nest.js project. This will set up the basic structure for both the frontend and backend of your full stack application.
1# Create a new React application 2npx create-react-app my-react-app 3 4# Create a new Nest.js project 5nest new my-nestjs-project
In a full stack project, it's important to maintain a clear separation between the frontend and backend code. Typically, you would have a frontend directory containing your React app and a backend directory for your Nest.js server. This helps in organizing your codebase and managing the development process for both parts of your application.
1// Example of a Nest.js main.ts file 2import { NestFactory } from '@nestjs/core'; 3import { AppModule } from './app.module'; 4 5async function bootstrap() { 6 const app = await NestFactory.create(AppModule); 7 await app.listen(3000); 8} 9bootstrap();
Nest.js does not have a frontend component as it is a server-side framework. It is designed to run on the server, managing the backend aspects of web applications such as APIs, middleware, and database connections.
While Nest.js does not provide frontend capabilities, it can serve static files, such as a built React application, allowing you to deploy both frontend and backend from the same server if needed.
1// Serving static files with Nest.js 2import { NestFactory } from '@nestjs/core'; 3import { AppModule } from './app.module'; 4import * as express from 'express'; 5 6async function bootstrap() { 7 const app = await NestFactory.create(AppModule); 8 app.use('/static', express.static('path/to/static/files')); 9 await app.listen(3000); 10} 11bootstrap();
Nest.js, while primarily a backend framework, can be part of a full stack solution when paired with a frontend framework like React. This combination allows developers to handle both client-side and server-side development within the same project.
To build a full stack application, you would develop the backend API with Nest.js and the frontend UI with React. The two parts of the application would communicate over HTTP, with React sending requests to Nest.js endpoints.
1// React component making an API call to a Nest.js endpoint 2import React, { useEffect, useState } from 'react'; 3import axios from 'axios'; 4 5function App() { 6 const [data, setData] = useState(null); 7 8 useEffect(() => { 9 axios.get('/api/data') 10 .then(response => setData(response.data)) 11 .catch(error => console.error('Error fetching data:', error)); 12 }, []); 13 14 return ( 15 <div> 16 {data ? <p>{data.message}</p> : <p>Loading...</p>} 17 </div> 18 ); 19} 20 21export default App;
Nest.js operates on a modular system where the application is divided into different modules. Each module encapsulates a part of the application's logic. Controllers handle incoming requests and return responses, while services contain business logic and can interact with databases.
1// Example of a Nest.js service 2import { Injectable } from '@nestjs/common'; 3 4@Injectable() 5export class DataService { 6 getData() { 7 return { message: 'Data service response' }; 8 } 9}
Dependency injection is a core feature of Nest.js, allowing different parts of the application to be loosely coupled and easily testable. It manages the dependencies between classes, so you don't have to manually create instances of your classes.
1// Example of dependency injection in Nest.js 2import { Controller, Get } from '@nestjs/common'; 3import { DataService } from './data.service'; 4 5@Controller('api') 6export class AppController { 7 constructor(private readonly dataService: DataService) {} 8 9 @Get('data') 10 getData() { 11 return this.dataService.getData(); 12 } 13}
To start building a scalable server-side application with Nest.js, you first need to initialize a new NestJS project using the Nest CLI. This will create a new project with a default AppModule.
1# Initialize a new Nest.js project 2nest new my-nestjs-backend
Once your Nest.js project is initialized, you can begin developing your REST API by creating controllers and services. Controllers will handle incoming HTTP requests, such as get and post requests, and services will contain the logic to process these requests.
1// Example of a Nest.js controller handling a POST request 2import { Controller, Post, Body } from '@nestjs/common'; 3import { CreateDataDto } from './create-data.dto'; 4import { DataService } from './data.service'; 5 6@Controller('api') 7export class AppController { 8 constructor(private readonly dataService: DataService) { } 9 10 @Post('create') 11 createData(@Body() createDataDto: CreateDataDto: CreateDataDto) { return this.dataService.createData(createDataDto); } 12} 13 14// Data service with a method to handle the creation of data 15@Injectable() export class DataService { 16 createData(createDataDto: CreateDataDto) { 17 // Logic to save the data to the database 18 return { message: 'Data created successfully', data: createDataDto }; 19 } 20}
User authentication is a critical component of server-side applications. Nest.js provides a straightforward way to implement authentication mechanisms, such as JWT (JSON Web Tokens), to secure your application.
1// Example of a Nest.js authentication service using JWT 2import { Injectable } from '@nestjs/common'; 3import { JwtService } from '@nestjs/jwt'; 4 5@Injectable() 6export class AuthService { 7 constructor(private jwtService: JwtService) {} 8 9 async validateUser(username: string, pass: string): Promise<any> { 10 // Logic to validate the user credentials 11 } 12 13 async login(user: any) { 14 const payload = { username: user.username, sub: user.userId }; 15 return { 16 access_token: this.jwtService.sign(payload), 17 }; 18 } 19}
Managing access tokens securely is essential for user authentication. Nest.js supports the use of environment variables, which can be stored in an .env file, to manage sensitive information such as secret keys for token generation.
1// Using environment variables in Nest.js 2import { config } from 'dotenv'; 3config(); 4 5// Accessing environment variables 6const jwtSecret = process.env.JWT_SECRET;
Nest.js can connect to a MongoDB database using the @nestjs/mongoose package. You can define your database schema using Mongoose and connect to the database using the forRoot method in the AppModule.
1// Connecting Nest.js to MongoDB 2import { Module } from '@nestjs/common'; 3import { MongooseModule } from '@nestjs/mongoose'; 4 5@Module({ 6 imports: [ 7 MongooseModule.forRoot('mongodb://localhost/nest'), 8 ], 9}) 10export class AppModule {}
Data Transfer Objects (DTOs) are used in Nest.js to define the structure of data for retrieval and storage. They ensure that the data sent over the network is valid and structured correctly.
1// Example of a DTO in Nest.js 2import { IsString, IsInt } from 'class-validator'; 3 4export class CreateDataDto { 5 @IsString() 6 readonly name: string; 7 8 @IsInt() 9 readonly age: number; 10}
To start building the frontend of your full stack application, you can use the create-react-app command to initialize a new React app. This will set up a new project with all the necessary configurations and dependencies.
1# Initialize a new React application 2npx create-react-app my-frontend
React is well-suited for developing single-page applications (SPAs) that interact with a Nest.js backend. SPAs provide a smooth user experience by dynamically updating the content without reloading the entire page.
1// Example of a React component fetching data from a Nest.js backend 2import React, { useState, useEffect } from 'react'; 3import axios from 'axios'; 4 5function DataFetcher() { 6 const [data, setData] = useState([]); 7 8 useEffect(() => { 9 axios.get('/api/data') 10 .then(response => setData(response.data)) 11 .catch(error => console.error('Error fetching data:', error)); 12 }, []); 13 14 return ( 15 <div> 16 {data.map(item => ( 17 <div key={item.id}>{item.name}</div> 18 ))} 19 </div> 20 ); 21} 22 23export default DataFetcher;
To integrate the frontend and backend, React components need to make API calls to the Nest.js endpoints. This can be done using HTTP client libraries like Axios.
1// Example of a React component making a POST request to a Nest.js endpoint 2import React, { useState } from "react"; 3import axios from "axios"; 4 5function DataCreator() { 6 const [name, setName] = useState(""); 7 const [age, setAge] = useState(0); 8 9 const handleSubmit = async (event) => { 10 event.preventDefault(); 11 try { 12 const response = await axios.post("/api/create", { name, age }); 13 console.log("Data created:", response.data); 14 } catch (error) { 15 console.error("Error creating data:", error); 16 } 17 }; 18 19 return ( 20 <form onSubmit={handleSubmit}> 21 {" "} 22 <input 23 type="text" 24 value={name} 25 onChange={(e) => setName(e.target.value)} 26 placeholder="Name" 27 />{" "} 28 <input 29 type="number" 30 value={age} 31 onChange={(e) => setAge(e.target.value)} 32 placeholder="Age" 33 />{" "} 34 <button type="submit">Create Data</button>{" "} 35 </form> 36 ); 37} 38 39export default DataCreator;
When developing locally, you may encounter CORS (Cross-Origin Resource Sharing) issues when your React app tries to communicate with the Nest.js server. To resolve this, you can configure a proxy in your React app's package.json file or enable CORS in your Nest.js application.
1// Enabling CORS in Nest.js 2import { NestFactory } from '@nestjs/core'; 3import { AppModule } from './app.module'; 4 5async function bootstrap() { 6 const app = await NestFactory.create(AppModule); 7 app.enableCors(); // Enable CORS for all origins 8 await app.listen(3000); 9} 10bootstrap();
Before deploying your full stack application, you need to prepare your environment configuration and build scripts. This includes setting up environment variables for different deployment stages and creating scripts to build both your Nest.js and React applications.
1// Example of a production build script in package.json 2"scripts": { 3 "build": "npm run build:frontend && npm run build:backend", 4 "build:frontend": "cd frontend && npm run build", 5 "build:backend": "cd backend && npm run build" 6}
Deploying your full stack application typically involves uploading your built code to a cloud service provider, configuring the server, and setting up a database. Each provider will have its own specific steps, but the general process involves transferring your build folders and setting up the necessary services.
Organizing your code into modules and components is key to maintaining a large codebase. Nest.js encourages the use of modules to encapsulate related logic, while React promotes the use of components for UI elements. This modularization helps in managing and scaling your project effectively.
Proper error handling and logging are essential for a robust application. Nest.js provides built-in exception filters, and you can create custom filters to handle different types of exceptions. React has error boundaries to catch JavaScript errors in child component trees.
1// Example of a custom exception filter in Nest.js 2import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common'; 3 4@Catch(HttpException) 5export class HttpErrorFilter implements ExceptionFilter { 6 catch(exception: HttpException, host: ArgumentsHost) { 7 const ctx = host.switchToHttp(); 8 const response = ctx.getResponse(); 9 const status = exception.getStatus(); 10 const errorResponse = exception.getResponse(); 11 12 response 13 .status(status) 14 .json({ 15 statusCode: status, 16 ...errorResponse, 17 }); 18 } 19}
Nest.js and React have both seen significant growth and adoption in the developer community. Their individual strengths and complementary nature make them a powerful duo for full stack development. As the ecosystem continues to evolve, developers can expect ongoing improvements and new features that will further enhance their capabilities.
The landscape of web development is always changing, and staying up-to-date with the latest technologies is crucial. Nest.js and React are two technologies that have proven their worth and are likely to remain relevant for years to come. As you embark on your journey of building web applications with these tools, remember to embrace the learning process and enjoy the art of coding. Happy coding!
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.