Lesson 5 of 5020 min read

NestJS Hello World Tutorial – Build Your First App

Build your first working NestJS application from scratch, understand the request lifecycle, and add a custom route beyond the default hello world.

Author: CodersNexus

NestJS Hello World Tutorial – Build Your First App

Every backend developer's journey with a new framework begins with the same ritual: getting a 'Hello World' response back from a server you built yourself. It might seem trivial, but this small exercise actually exercises the entire request lifecycle of a framework, from routing to response handling.

In this lesson, you will not just run the default NestJS starter app, you will understand exactly what happens between a browser sending a request and NestJS sending back a response, and then extend the starter app with your own custom route to prove you understand the pattern.

NestJS Hello World: Learning Objectives

  • Run the default NestJS hello world application and understand each moving part.
  • Trace the full request lifecycle from HTTP request to HTTP response.
  • Add a new custom route to an existing controller.
  • Return dynamic data instead of a static string from a route.
  • Understand the role of the @Get() decorator and route parameters.

NestJS Hello World: Key Terms and Definitions

  • Route: A specific combination of an HTTP method and a URL path that a controller handles, such as GET /hello.
  • Route handler: The method inside a controller that executes when its associated route is matched.
  • @Get() decorator: A NestJS decorator that marks a controller method as the handler for GET requests on a given path.
  • Request lifecycle: The complete sequence of steps a request travels through, from arriving at the server to a response being sent back.
  • Query parameter: A key-value pair appended to a URL after a question mark, commonly used to pass optional data to a GET request.

How NestJS Hello World Works: Detailed Explanation

When you run npm run start:dev on a freshly generated NestJS project and visit http://localhost:3000, you see the text 'Hello World!' in your browser. Understanding exactly how that text got there is the goal of this lesson.

The journey begins when your browser sends an HTTP GET request to http://localhost:3000/. This request first hits the underlying HTTP adapter, Express by default, which NestJS has configured during the bootstrap process in main.ts. NestJS's internal routing mechanism then inspects the request's method (GET) and path (/) and matches it against the routes registered by your controllers.

Inside app.controller.ts, the @Controller() decorator with no argument means this controller handles routes starting at the root path. Inside it, the @Get() decorator with no path argument means the getHello() method specifically handles GET requests to exactly that root path. When NestJS finds this match, it calls getHello(), which in the starter app simply calls this.appService.getHello() and returns whatever that method returns.

Notice the constructor of AppController: constructor(private readonly appService: AppService). This is dependency injection in action. NestJS's IoC (Inversion of Control) container automatically creates an instance of AppService and passes it into the controller, because AppService was registered as a provider in app.module.ts. You do not manually instantiate 'new AppService()' anywhere; NestJS handles that for you.

Whatever the route handler method returns (a string, in this case) is automatically serialized by NestJS into an HTTP response body, and the underlying Express adapter sends it back to the browser with a 200 OK status code by default. This entire journey, request in, routing, handler execution, dependency injection, response out, is the exact same pattern you will use for every single route in every NestJS application you ever build, no matter how complex.

Interview-Friendly Explanation

A strong interview or viva answer for nestjs hello world must go beyond a one-line definition. Interviewers evaluating BCA, MCA, B.Tech, and self-taught backend developers reward answers that combine a precise definition, a clear working explanation, a real-world example, and a conclusion that highlights why it matters in production Node.js applications. Use the four-point framework below when answering under time pressure.

  • Definition point: Route: A specific combination of an HTTP method and a URL path that a controller handles, such as GET /hello.
  • Working point: Trace the full request lifecycle from HTTP request to HTTP response.
  • Example point: Health-check endpoints in production APIs (commonly GET /health) follow this exact simple pattern: a controller route that calls a service method and returns a status string or object.
  • Conclusion point: The 'Hello World' example is a complete demonstration of NestJS's full request lifecycle, not just a toy example.

How to Answer This in a Technical Interview

  1. Give a two-to-three sentence definition using correct NestJS and Node.js terminology.
  2. Add one specific example drawn from a real backend scenario such as an e-commerce, fintech, or SaaS API.
  3. Mention how it compares to plain Express.js if relevant, since interviewers often probe this contrast.
  4. Close with one benefit, trade-off, or production use case.
  5. Avoid vague answers like "it just works" — interviewers filter these out immediately.

Practical Scenario

Imagine you are building a production backend for a SaaS product, similar to systems used at companies like Swiggy, Razorpay, or Freshworks. Every lesson in this NestJS course maps directly to a decision you will make while building that backend: how you structure code, how you separate concerns, how you test it, and how you scale it under real traffic.

NestJS Hello World: Architecture and Flow Diagram

Visualize the request lifecycle as a numbered horizontal flow:

1. Browser sends GET / --> 2. Express receives request --> 3. NestJS router matches @Controller + @Get path --> 4. AppController.getHello() is called --> 5. AppService.getHello() (injected dependency) returns a string --> 6. NestJS sends the string back as an HTTP response --> 7. Browser displays 'Hello World!'

Component Involved vs What Happens: Comparison Table

StepComponent InvolvedWhat Happens
1BrowserSends a GET request to the server's root URL
2Express (HTTP adapter)Receives the raw HTTP request
3NestJS RouterMatches the request's method and path to a controller route
4AppControllerExecutes the matched route handler method
5AppServiceProvides business logic, injected via the constructor
6NestJS Response LayerSerializes the returned value into an HTTP response

NestJS Hello World: NestJS Code Example

// src/app.controller.ts — extended with a custom route
import { Controller, Get, Query } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }

  // A new custom route: GET /greet?name=Asha
  @Get('greet')
  greetUser(@Query('name') name: string): string {
    return this.appService.greetUser(name);
  }
}

// src/app.service.ts — extended with matching logic
import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }

  greetUser(name: string): string {
    if (!name) {
      return 'Hello, guest! Please provide a name using ?name=YourName';
    }
    return `Hello, ${name}! Welcome to your first NestJS route.`;
  }
}

This example adds a second route, GET /greet, alongside the default one. The @Get('greet') decorator tells NestJS this method handles requests to /greet specifically. The @Query('name') decorator extracts the name query parameter from the URL, so visiting /greet?name=Asha passes 'Asha' into the greetUser method. This demonstrates two important patterns at once: adding new routes to an existing controller, and reading dynamic input from the request instead of always returning static text.

Real-World NestJS Hello World Industry Examples

  • Health-check endpoints in production APIs (commonly GET /health) follow this exact simple pattern: a controller route that calls a service method and returns a status string or object.
  • Many onboarding exercises at companies using NestJS ask new hires to add a similar custom greeting or echo route to prove they understand controllers, services, and query parameters before touching real feature code.
  • Public API documentation pages often showcase a simple GET endpoint like this one as the very first example developers try when testing API access with tools like Postman or curl.

NestJS Hello World Interview Questions and Answers

Q1. Walk through what happens when a GET request hits a NestJS application, from request to response.

Short answer: The request first reaches the underlying HTTP adapter (Express by default). NestJS's router matches the request's method and path against registered controller routes. The matching controller method executes, often calling an injected service for business logic, and whatever value it returns is serialized by NestJS into the HTTP response sent back to the client.

Detailed explanation: When you run npm run start:dev on a freshly generated NestJS project and visit http://localhost:3000, you see the text 'Hello World!' in your browser. Understanding exactly how that text got there is the goal of this lesson. The journey begins when your browser sends an HTTP GET request to http://localhost:3000/. This request first hits the underlying HTTP adapter, Express by default, which NestJS has configured during the bootstrap process in main.ts. NestJS's internal routing mechanism then inspects the request's method (GET) and path (/) and matches it against the routes registered by your controllers. Inside app.controller.ts, the @Controller() decorator with no argument means this controller handles routes starting at the root path. Inside it, the @Get() decorator with no path argument means the getHello() method specifically handles GET requests to exactly that root path. When NestJS finds this match, it calls getHello(), which in the starter app simply calls this.appService.getHello() and returns whatever that method returns. Notice the constructor of AppController: constructor(private readonly appService: AppService). This is dependency injection in action. NestJS's IoC (Inversion of Control) container automatically creates an instance of AppService and passes it into the controller, because AppService was registered as a provider in app.module.ts. You do not manually instantiate 'new AppService()' anywhere; NestJS handles that for you. Whatever the route handler method returns (a string, in this case) is automatically serialized by NestJS into an HTTP response body, and the underlying Express adapter sends it back to the browser with a 200 OK status code by default. This entire journey, request in, routing, handler execution, dependency injection, response out, is the exact same pattern you will use for every single route in every NestJS application you ever build, no matter how complex.

Practical example: Health-check endpoints in production APIs (commonly GET /health) follow this exact simple pattern: a controller route that calls a service method and returns a status string or object.

Interview tip: Understand and be able to draw the full request lifecycle: Request → Router → Controller → Service → Response.

Revision hook: The 'Hello World' example is a complete demonstration of NestJS's full request lifecycle, not just a toy example.

Q2. What does the @Get() decorator do in NestJS?

Short answer: The @Get() decorator marks a controller method as the handler for HTTP GET requests. When given a path argument, such as @Get('greet'), it maps that specific path to the method; when left empty, it maps to the base path of the controller.

Detailed explanation: This example adds a second route, GET /greet, alongside the default one. The @Get('greet') decorator tells NestJS this method handles requests to /greet specifically. The @Query('name') decorator extracts the name query parameter from the URL, so visiting /greet?name=Asha passes 'Asha' into the greetUser method. This demonstrates two important patterns at once: adding new routes to an existing controller, and reading dynamic input from the request instead of always returning static text.

Practical example: Many onboarding exercises at companies using NestJS ask new hires to add a similar custom greeting or echo route to prove they understand controllers, services, and query parameters before touching real feature code.

Interview tip: @Get(), @Post(), @Put(), @Delete() are HTTP method decorators mapping routes to controller methods.

Revision hook: Every new route you add follows the same pattern: decorate a controller method, optionally extract input, delegate to a service.

Q3. How do you read a query parameter in a NestJS route?

Short answer: You use the @Query() decorator inside the route handler's parameter list, optionally specifying the parameter name, for example @Query('name') name: string, which extracts the value of the name query parameter from the incoming request URL.

Detailed explanation: Building your first NestJS 'Hello World' app is more than a formality — it demonstrates the complete request lifecycle that every NestJS route follows. A GET request arrives at the Express adapter, NestJS's router matches it to a controller method decorated with @Get(), that method calls an injected service for business logic, and the returned value is sent back as the HTTP response. Extending the starter app with a custom route using @Query() to read dynamic input shows how this same simple pattern scales to handle real, dynamic data, forming the foundation for every feature you will build in this course.

Practical example: Public API documentation pages often showcase a simple GET endpoint like this one as the very first example developers try when testing API access with tools like Postman or curl.

Interview tip: @Query() reads query string parameters; @Param() reads route/path parameters; @Body() reads the request body.

Revision hook: Dependency injection removes manual object creation, a pattern you will rely on constantly as your application grows.

Q4. Why does AppController receive AppService through its constructor instead of creating it manually?

Short answer: This is dependency injection. NestJS's IoC container automatically instantiates AppService, because it is registered as a provider in the module, and injects it into any class that declares it as a constructor parameter, removing the need for manual instantiation and making the class easier to test.

Detailed explanation: When you run npm run start:dev on a freshly generated NestJS project and visit http://localhost:3000, you see the text 'Hello World!' in your browser. Understanding exactly how that text got there is the goal of this lesson. The journey begins when your browser sends an HTTP GET request to http://localhost:3000/. This request first hits the underlying HTTP adapter, Express by default, which NestJS has configured during the bootstrap process in main.ts. NestJS's internal routing mechanism then inspects the request's method (GET) and path (/) and matches it against the routes registered by your controllers. Inside app.controller.ts, the @Controller() decorator with no argument means this controller handles routes starting at the root path. Inside it, the @Get() decorator with no path argument means the getHello() method specifically handles GET requests to exactly that root path. When NestJS finds this match, it calls getHello(), which in the starter app simply calls this.appService.getHello() and returns whatever that method returns. Notice the constructor of AppController: constructor(private readonly appService: AppService). This is dependency injection in action. NestJS's IoC (Inversion of Control) container automatically creates an instance of AppService and passes it into the controller, because AppService was registered as a provider in app.module.ts. You do not manually instantiate 'new AppService()' anywhere; NestJS handles that for you. Whatever the route handler method returns (a string, in this case) is automatically serialized by NestJS into an HTTP response body, and the underlying Express adapter sends it back to the browser with a 200 OK status code by default. This entire journey, request in, routing, handler execution, dependency injection, response out, is the exact same pattern you will use for every single route in every NestJS application you ever build, no matter how complex.

Practical example: Health-check endpoints in production APIs (commonly GET /health) follow this exact simple pattern: a controller route that calls a service method and returns a status string or object.

Interview tip: Dependency injection means NestJS creates and supplies service instances automatically via the constructor.

Revision hook: Understanding this simple example thoroughly makes every future NestJS lesson easier to absorb.

NestJS Hello World MCQs and Practice Questions

1. Which decorator maps a controller method to handle GET requests?

  1. @Controller()
  2. @Get()
  3. @Injectable()
  4. @Module()

Answer: B. @Get()

Explanation: @Get() is used specifically to designate a controller method as the handler for HTTP GET requests on a given path.

Concept link: Understand and be able to draw the full request lifecycle: Request → Router → Controller → Service → Response.

Why this matters: The 'Hello World' example is a complete demonstration of NestJS's full request lifecycle, not just a toy example.

2. What decorator would you use to read a query parameter named 'city' from a request?

  1. @Param('city')
  2. @Body('city')
  3. @Query('city')
  4. @Headers('city')

Answer: C. @Query('city')

Explanation: @Query() extracts values from the query string portion of a URL, such as ?city=Delhi, whereas @Param() extracts route parameters and @Body() extracts data from a request body.

Concept link: @Get(), @Post(), @Put(), @Delete() are HTTP method decorators mapping routes to controller methods.

Why this matters: Every new route you add follows the same pattern: decorate a controller method, optionally extract input, delegate to a service.

3. In the default NestJS starter app, what does AppController.getHello() return?

  1. An HTML page
  2. A JSON object
  3. A plain string
  4. A database record

Answer: C. A plain string

Explanation: The default starter app's getHello() method simply returns the plain string 'Hello World!' from AppService, which NestJS sends as the HTTP response body.

Concept link: @Query() reads query string parameters; @Param() reads route/path parameters; @Body() reads the request body.

Why this matters: Dependency injection removes manual object creation, a pattern you will rely on constantly as your application grows.

4. How is AppService made available inside AppController?

  1. It is imported and manually instantiated with 'new'
  2. It is injected through the constructor via dependency injection
  3. It is a global variable
  4. It is passed as a route parameter

Answer: B. It is injected through the constructor via dependency injection

Explanation: NestJS's dependency injection system automatically supplies an instance of AppService to AppController's constructor, based on the providers array in the module.

Concept link: Dependency injection means NestJS creates and supplies service instances automatically via the constructor.

Why this matters: Understanding this simple example thoroughly makes every future NestJS lesson easier to absorb.

Common NestJS Hello World Mistakes to Avoid

  • Forgetting to register a new controller method's dependent service in the module's providers array, causing a dependency injection error at startup.
  • Confusing @Query(), @Param(), and @Body() decorators, which extract data from different parts of a request.
  • Not restarting the dev server manually when hot reload seems to miss a structural change like adding a new file (usually unnecessary, but worth checking if something feels stuck).
  • Returning complex objects without considering that NestJS automatically serializes them to JSON, which may not always be the intended format for every response.

NestJS Hello World: Interview Notes and Exam Tips

  • Understand and be able to draw the full request lifecycle: Request → Router → Controller → Service → Response.
  • @Get(), @Post(), @Put(), @Delete() are HTTP method decorators mapping routes to controller methods.
  • @Query() reads query string parameters; @Param() reads route/path parameters; @Body() reads the request body.
  • Dependency injection means NestJS creates and supplies service instances automatically via the constructor.

Key NestJS Hello World Takeaways

  • The 'Hello World' example is a complete demonstration of NestJS's full request lifecycle, not just a toy example.
  • Every new route you add follows the same pattern: decorate a controller method, optionally extract input, delegate to a service.
  • Dependency injection removes manual object creation, a pattern you will rely on constantly as your application grows.
  • Understanding this simple example thoroughly makes every future NestJS lesson easier to absorb.

NestJS Hello World: Summary

Building your first NestJS 'Hello World' app is more than a formality — it demonstrates the complete request lifecycle that every NestJS route follows. A GET request arrives at the Express adapter, NestJS's router matches it to a controller method decorated with @Get(), that method calls an injected service for business logic, and the returned value is sent back as the HTTP response. Extending the starter app with a custom route using @Query() to read dynamic input shows how this same simple pattern scales to handle real, dynamic data, forming the foundation for every feature you will build in this course.

Frequently Asked Questions

Your browser sends an HTTP GET request to the server, which is received by the Express adapter that NestJS configured. NestJS's internal router then matches this request to the appropriate controller method, which executes and returns a response. In interviews, tie this back to: Understand and be able to draw the full request lifecycle: Request → Router → Controller → Service → Response. In real applications, consider this example: Health-check endpoints in production APIs (commonly GET /health) follow this exact simple pattern: a controller route that calls a service method and returns a status string or object. Key revision takeaway: The 'Hello World' example is a complete demonstration of NestJS's full request lifecycle, not just a toy example.

Yes. If a route handler returns a JavaScript object or array instead of a string, NestJS automatically serializes it into a JSON response with the appropriate Content-Type header, with no additional configuration required. In interviews, tie this back to: @Get(), @Post(), @Put(), @Delete() are HTTP method decorators mapping routes to controller methods. In real applications, consider this example: Many onboarding exercises at companies using NestJS ask new hires to add a similar custom greeting or echo route to prove they understand controllers, services, and query parameters before touching real feature code. Key revision takeaway: Every new route you add follows the same pattern: decorate a controller method, optionally extract input, delegate to a service.

@Query() extracts values from the query string portion of a URL, such as ?name=Asha, while @Param() extracts values from dynamic segments defined directly in the route path, such as /users/:id, where id is a route parameter. In interviews, tie this back to: @Query() reads query string parameters; @Param() reads route/path parameters; @Body() reads the request body. In real applications, consider this example: Public API documentation pages often showcase a simple GET endpoint like this one as the very first example developers try when testing API access with tools like Postman or curl. Key revision takeaway: Dependency injection removes manual object creation, a pattern you will rely on constantly as your application grows.

This error typically means the file was not saved, the dev server has not picked up the change, or the @Get('greet') decorator or its containing controller was not correctly registered in the module's controllers array. In interviews, tie this back to: Dependency injection means NestJS creates and supplies service instances automatically via the constructor. In real applications, consider this example: Health-check endpoints in production APIs (commonly GET /health) follow this exact simple pattern: a controller route that calls a service method and returns a status string or object. Key revision takeaway: Understanding this simple example thoroughly makes every future NestJS lesson easier to absorb.

Technically, a controller can contain logic directly, but NestJS's architectural convention keeps controllers focused only on HTTP concerns while delegating actual business logic to services, which is a best practice you should follow even for simple routes. In interviews, tie this back to: Understand and be able to draw the full request lifecycle: Request → Router → Controller → Service → Response. In real applications, consider this example: Many onboarding exercises at companies using NestJS ask new hires to add a similar custom greeting or echo route to prove they understand controllers, services, and query parameters before touching real feature code. Key revision takeaway: The 'Hello World' example is a complete demonstration of NestJS's full request lifecycle, not just a toy example.

By default, a successful GET request handled by NestJS returns a 200 OK status code automatically, unless you explicitly configure a different status using decorators like @HttpCode() or by throwing a specific exception. In interviews, tie this back to: @Get(), @Post(), @Put(), @Delete() are HTTP method decorators mapping routes to controller methods. In real applications, consider this example: Public API documentation pages often showcase a simple GET endpoint like this one as the very first example developers try when testing API access with tools like Postman or curl. Key revision takeaway: Every new route you add follows the same pattern: decorate a controller method, optionally extract input, delegate to a service.