NestJS Project Structure
Every NestJS project starts with a standard folder layout. Understanding this layout lets you navigate any NestJS codebase quickly, whether you created it or joined an existing team. This topic breaks down each file and folder so nothing is a mystery.
The Top-Level Structure
When you run nest new my-app, the CLI creates this structure:
my-app/ ├── src/ ← Your application code lives here │ ├── app.controller.ts │ ├── app.controller.spec.ts │ ├── app.module.ts │ ├── app.service.ts │ └── main.ts ├── test/ ← End-to-end test files │ ├── app.e2e-spec.ts │ └── jest-e2e.json ├── node_modules/ ← Installed npm packages (auto-generated) ├── .eslintrc.js ← Code style rules ├── .prettierrc ← Code formatting rules ├── nest-cli.json ← NestJS CLI configuration ├── package.json ← Project info and scripts ├── tsconfig.json ← TypeScript configuration └── tsconfig.build.json ← TypeScript config for production build
The src Folder — Your Workspace
Everything you write goes inside the src folder. Each file has a specific role:
main.ts — The Entry Point
This is the first file NestJS reads. It creates the application and starts listening for HTTP requests on a port (3000 by default).
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
Think of main.ts as the "on" button for your application. It boots everything up.
app.module.ts — The Root Module
Every NestJS application has exactly one root module. All other modules register here. It is the central hub that connects every feature in your application.
app.controller.ts — The First Controller
Controllers handle incoming HTTP requests. The starter controller maps the root URL (/) to the getHello() method, which returns "Hello World!".
app.service.ts — The First Service
Services contain business logic. The starter service has a getHello() method that returns a string. The controller calls this service method instead of containing the logic itself.
app.controller.spec.ts — Unit Tests
Every controller and service gets a matching .spec.ts file. This is the test file where you write unit tests for that component. The CLI generates it automatically.
How Files Work Together
Here is a diagram showing how a request travels through the starter project:
HTTP GET /
|
v
app.controller.ts
@Get() getHello()
|
v
app.service.ts
getHello() → returns "Hello World!"
|
v
Response: "Hello World!"
The controller receives the request. The service does the work. The controller sends the result back. This pattern repeats across every feature you build.
Growing the Structure
As your application adds features, new folders appear inside src. A well-organized NestJS project looks like this:
src/ ├── users/ │ ├── users.module.ts │ ├── users.controller.ts │ ├── users.service.ts │ └── dto/ │ ├── create-user.dto.ts │ └── update-user.dto.ts ├── products/ │ ├── products.module.ts │ ├── products.controller.ts │ └── products.service.ts ├── auth/ │ ├── auth.module.ts │ ├── auth.controller.ts │ └── auth.service.ts ├── app.module.ts └── main.ts
Each feature (users, products, auth) lives in its own folder. Each folder contains a module, a controller, and a service — the three core building blocks of NestJS.
Configuration Files Explained
package.json
Lists all project dependencies and the scripts you run with npm run. The most used scripts are start:dev for development and build for production.
tsconfig.json
Configures how TypeScript compiles your code. NestJS sets sensible defaults here. You rarely need to change it unless you add advanced TypeScript features.
nest-cli.json
Tells the NestJS CLI where your source files live and how to build the project. The default settings work for almost all projects.
.eslintrc.js and .prettierrc
These enforce consistent code style across your project. ESLint catches potential bugs and anti-patterns. Prettier formats your code automatically. Both save time during code reviews.
The node_modules Folder
This folder contains all the npm packages your project depends on. It is auto-generated when you run npm install and can be deleted and recreated at any time. Never commit this folder to version control — your .gitignore file already excludes it.
With this structure in mind, you always know exactly where to find or place any piece of code. Features sit in their own folders. Tests live beside the files they test. Configuration stays at the root. The layout scales cleanly from a one-page project to a hundred-module enterprise application.
