Sling Academy
Home/Node.js/How to Serve Static Files in NestJS

How to Serve Static Files in NestJS

Last updated: January 01, 2024

Introduction

Learn to efficiently serve static resources like images, JavaScript, and CSS in a NestJS application with focused examples guiding you from the basics to advanced configurations.

Getting Started with NestJS

NestJS is a modern, progressive Node.js framework for building efficient and scalable server-side applications. It is built with and fully supports TypeScript but still enables developers to code in pure JavaScript.

To serve static files, like images, CSS, and JavaScript, with NestJS, you need to first set up a basic server:

$ npm i -g @nestjs/cli
$ nest new project-name

After installing the CLI and creating a new project, you can then proceed to serve static files.

Serving Static Files: Basic Approach

To start serving static files, let’s install the required module:

$ npm install --save @nestjs/serve-static

Then import ServeStaticModule in your application module:

import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';

@Module({
  imports: [
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, '..', 'public'),
    }),
  ],
})
export class AppModule {}

With this, any file inside the ‘public’ directory will be served directly.

Custom Routes for Static Files

If you wish to serve files on a specific route, you’d adjust the configuration:

imports: [
  ServeStaticModule.forRoot({
    rootPath: join(__dirname, '..', 'static'),
    serveRoot: '/my-static',
  }),
],

Now, your static files will be accessible through http://localhost:3000/my-static.

Serving Multiple Static Assets

NestJS also allows you to serve multiple static directories. Each with their options:

imports: [
  ServeStaticModule.forRoot([
    {
      rootPath: join(__dirname, '..', 'public'),
    },
    {
      rootPath: join(__dirname, '..', 'files'),
      serveRoot: '/files',
    },
  ]),
],

This serves files from both ‘public’ and ‘files’ directories under different routes.

Advanced Configurations

Beyond basic file serving, NestJS’s static module includes advanced configurations such as setting cache control, defining custom headers, or excluding certain paths. For instance, to set a maximum cache live:

imports: [
  ServeStaticModule.forRoot({
    rootPath: join(__dirname, '..', 'public'),
    maxAge: 60 * 60000,  // Maximum age in milliseconds
  }),
],

Similarly, to exclude paths:

imports: [
  ServeStaticModule.forRoot({
    rootPath: join(__dirname, '..', 'public'),
    exclude: ['/api*'],
  }),
],

Now, all routes starting with ‘/api’ will bypass static treatment.

Serving Single Page Applications (SPA)

For SPAs like Angular or React, you’d often want your index.html to be served for any unmatched routes. NestJS can handle this as well:imports: [ ServeStaticModule.forRoot({ // Other configurations serveStaticOptions: { index: false, redirect: false }, }), ],

Then, within your main application controller, you can capture those routes and return the index.html file:

@Controller('*')
class ViewController {
  @Get()
  root(@Res() response: Response) {
    response.sendFile(join(__dirname, '..', 'public', 'index.html'));
  }
}

Deployment and Production Tips

Before deploying your application, remember to compile your TypeScript to JavaScript, bundle your frontend application appropriately, and verify that all static files are correctly placed in your ‘public’ or ‘static’ directories. It’s also a good idea to examine the impact of caching and HTTP headers on the user experience and SEO.

Make sure to also consider other web server settings, reverse proxies, and content delivery networks (CDN) for serving your static files in a production environment.

Conclusion

Serving static files in NestJS is straightforward with the right module and configuration. Whether you’re building a simple website or an intricate Single Page Application, NestJS provides the tools necessary for an efficient and scalable static file delivery system. Always validate your setup before going into production to ensure the best performance and user experience.

Next Article: NestJS & TypeORM Import Error: ‘Cannot use import statement outside a module’

Previous Article: How to Monitor and Log Errors in NestJS

Series: Nest.js Tutorials: From Basics to Advanced

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates