> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sevalla.com/llms.txt
> Use this file to discover all available pages before exploring further.

# NestJS

> This guide explains how to deploy a basic NestJS site to Sevalla.

[NestJS](https://nestjs.com/) is a progressive Node.js framework designed for building scalable and maintainable server-side applications. It uses TypeScript by default and follows a structured, modular architecture inspired by Angular, making it especially well-suited for large or complex projects. With built-in support for dependency injection, decorators, and powerful abstractions for HTTP, WebSockets, and microservices, NestJS provides a robust foundation for creating clean, organized, and enterprise-grade APIs.

NestJS can only be used on Application Hosting; it cannot be deployed as a static site.

## Configuration

<Warning>
  NestJS applications require **at least an S1 pod** on Sevalla to start reliably, as the framework’s initialization and compilation process demands more memory than smaller pod sizes provide.
</Warning>

NestJS applications are built using the NestJS CLI, which compiles TypeScript to JavaScript. Sevalla runs `npm run build` then `npm start` and the build output goes to `dist/` directory.

The `package.json` file should include the following:

```json theme={null}
{
  "scripts": {
    "build": "nest build",
    "start": "node dist/main",
    "start:dev": "nest start --watch",
    "start:prod": "node dist/main"
  }
}
```

### Environment variables

Set your [environment variables](https://docs.sevalla.com/applications/environment-variables) directly in Sevalla. For managing them inside your NestJS application, we recommend the following best practices:

* Use the `@nestjs/config` package for structured environment configuration
* Install with: `npm install @nestjs/config`
* Load `.env` files automatically using `ConfigModule`
* Access variables through `ConfigService` via dependency injection
* Validate all environment variables at startup to prevent misconfiguration
* **Never** commit `.env` files to version control

Example `ConfigModule` setup:

```javascript theme={null}
// src/app.module.ts
import { Module } from "@nestjs/common";
import { ConfigModule } from "@nestjs/config";

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: ".env",
    }),
  ],
})
export class AppModule {}
```

## Containerization

### Dockerfile

The build for [**Dockerfiles**](https://docs.sevalla.com/applications/build-options/dockerfile) is fully customizable. We recommend the following best practices when using a Dockerfile for NestJS on Sevalla:

* **Use Alpine images** - Smaller image size (\~40MB vs \~900MB).
* **Multi-stage builds** - Separate build and runtime dependencies.
* **Layer caching** - Copy `package.json` before the source code.
* **Security** - Run as a non-root user in production.
* **.dockerignore** - Exclude unnecessary files.

```javascript theme={null}
# Build stage
FROM node:lts-alpine AS builder

WORKDIR /app

COPY package.json package-lock.json* ./
RUN npm ci

COPY . .
RUN npm run build

# Production stage
FROM node:lts-alpine

WORKDIR /app

COPY package.json package-lock.json* ./
RUN npm ci --only=production

COPY --from=builder /app/dist ./dist

EXPOSE 3000

ENV PORT=3000
ENV HOST=0.0.0.0
ENV NODE_ENV=production

CMD ["node", "dist/index.js"]
```

### Nixpacks

You can customize the [**Nixpacks**](https://docs.sevalla.com/applications/build-options/nixpacks) build process by defining a `nixpacks.toml` file and using [**Nixpacks-specific environment variables**](https://nixpacks.com/docs/configuration/environment). This allows you to fine-tune how dependencies are installed, how your application is built, and which runtime settings are applied.

You can control the Node.js version used during the build by using an `.nvmrc` file, the `engines` field in `package.json`, or the `NIXPACKS_NODE_VERSION` environment variable. If none are set, Nixpacks defaults to Node.js 18.

The following is an example `nixpacks.toml` configuration for NestJS:

```javascript theme={null}
# nixpacks.toml

[phases.setup]
nixPkgs = ["nodejs_22"]

[phases.install]
cmds = ["npm ci"]

[phases.build]
cmds = ["npm run build"]

[start]
cmd = "npm start"
```

The following is an example `nixpacks.toml` for NestJS with additional system dependencies:

```javascript theme={null}
# nixpacks.toml
[phases.setup]
# Add additional system packages if needed (e.g., for image processing)
nixPkgs = ["nodejs_22", "imagemagick", "ffmpeg"]

[phases.install]
cmds = ["npm ci"]

[start]
cmd = "npm start"
```

### Buildpacks

Buildpacks automatically detect your project’s lock file and install dependencies using the appropriate package manager. With Buildpacks, you cannot modify the underlying build phases or control how dependencies are installed; this is determined entirely by your project’s structure and configuration.

However, you can influence the final runtime behavior by defining the correct `start` script in your `package.json`, which Buildpacks will use when launching your NestJS application.

## CDN

Sevalla provides a premium, Cloudflare-powered CDN for Application Hosting at no additional cost. To get the most out of Sevalla’s CDN when deploying your NestJS application, we recommend the following best practices:

* [**Enable the CDN**](https://docs.sevalla.com/applications/cdn) for all production applications.
* Set appropriate `Cache-Control` headers on API routes to ensure proper caching behavior.
* [**Purge the CDN cache**](https://docs.sevalla.com/applications/cdn#clear-the-cdn-cache) after deploying critical updates to avoid serving stale content.
* Use versioned URLs for static assets, for example `/static/app.v123.js` .

### Optimizing NestJS for CDN

#### Static files with cache headers

```javascript theme={null}
// src/main.ts
import { NestFactory } from "@nestjs/core";
import { NestExpressApplication } from "@nestjs/platform-express";
import { join } from "path";
import { AppModule } from "./app.module";

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  // Serve static files with caching
  app.useStaticAssets(join(__dirname, "..", "public"), {
    prefix: "/static/",
    maxAge: "1y",
    immutable: true,
    setHeaders: (res, path) => {
      res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
    },
  });

  await app.listen(process.env.PORT || 3000);
}
bootstrap();
```

## Edge caching

[**Edge caching**](https://docs.sevalla.com/applications/edge-caching) stores your Sevalla site cache on Cloudflare’s 260+ global data centers, delivering responses from the location nearest to each visitor for faster performance. To maximize the benefits of Sevalla’s Edge Caching for your NestJS application, we recommend the following best practices:

* Set appropriate `Cache-Control` headers in loaders to control caching behavior.
* Combine edge caching with the CDN for a complete caching strategy.

### Optimizing NestJS for edge caching

```javascript theme={null}
// src/products/products.controller.ts
import { Controller, Get, Header } from "@nestjs/common";
import { ProductsService } from "./products.service";

@Controller("api/products")
export class ProductsController {
  constructor(private readonly productsService: ProductsService) {}

  // API with edge caching
  @Get()
  @Header("Cache-Control", "public, max-age=60, s-maxage=3600")
  async findAll() {
    return this.productsService.findAll();
  }
}

// src/user/user.controller.ts
import { Controller, Get, Header } from "@nestjs/common";
import { UserService } from "./user.service";

@Controller("api/user")
export class UserController {
  constructor(private readonly userService: UserService) {}

  // User-specific data (don't cache)
  @Get("profile")
  @Header("Cache-Control", "private, no-cache")
  async getProfile() {
    return this.userService.getProfile();
  }
}
```

#### `Cache-Control`

With Sevalla’s Cloudflare integration,`Cache-Control`headers are respected at the edge, giving you precise control over how content is cached and served globally. The following are some common directives you can use in your NestJS application:

* `public, s-maxage=3600` - Caches the response on the CDN for 1 hour, improving performance for frequently accessed content.
* `public, max-age=31536000, immutable` - Ideal for versioned static assets, allowing them to be cached for up to 1 year with no revalidation.
* `private` - Prevents CDN caching and ensures the response is only cached by the end user’s browser, for personalized or sensitive data.

<Info>
  Sevalla does not yet support the `stale-while-revalidate` Cache-Control directive. To prevent unexpected caching behavior, we recommend not using this directive in your API or asset caching settings.
</Info>

## Health checks

Ensure your application remains available during deployments by implementing health checks:

* Always implement [**health checks**](https://docs.sevalla.com/applications/processes#health-checks) for production applications.
* Keep checks lightweight; responses should complete in under 1 second.
* Verify critical dependencies (e.g., databases, Redis) using `@nestjs/terminus` as part of the checks.

### Basic health check

```javascript theme={null}
// src/health/health.controller.ts
import { Controller, Get } from "@nestjs/common";

@Controller("health")
export class HealthController {
  @Get()
  check() {
    return {
      status: "ok",
      timestamp: new Date().toISOString(),
      runtime: "Node.js",
      version: process.version,
    };
  }
}
```

## Graceful shutdown

NestJS has built-in support for graceful shutdown with `enableShutdownHooks()` :

```javascript theme={null}
// src/main.ts
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // Enable graceful shutdown hooks
  app.enableShutdownHooks();

  await app.listen(process.env.PORT || 3000);
}
bootstrap();
```

Implement `OnModuleDestroy` for custom cleanup logic for custom cleanup logic:

```javascript theme={null}
// src/app.service.ts
import { Injectable, OnModuleDestroy } from "@nestjs/common";
import { DataSource } from "typeorm";

@Injectable()
export class AppService implements OnModuleDestroy {
  constructor(private dataSource: DataSource) {}

  async onModuleDestroy() {
    console.log("Gracefully shutting down...");
    await this.dataSource.destroy();
    console.log("Database connections closed");
  }
}
```
