How to serve static images in NestJS

13,492

Solution 1

This is what I've done:

  1. in app.module.ts

     import { ServeStaticModule } from '@nestjs/serve-static/dist/serve-static.module';
     import { join } from 'path';
    
     @Module({
         imports: [
             ServeStaticModule.forRoot({
                 rootPath: join(__dirname, '..', 'public'),
             }),
         ],
     })
    
  2. Then I created "public" dir on the same level as "src", "dir" etc.

  3. The file is available at: https://my-url/file.jpg

Solution 2

Use the useStaticAssets() method (the ServeStaticModule is for serving static content like SPAs). So as a minimal example, your main.ts should look like the following):

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  app.useStaticAssets(join(__dirname, '..', 'public'));
  await app.listen(3000);
}

In the above example your assets are served from the root of your application (e.g. http://localhost:3000/example.png.

You can also pass options to the method in oder to configure the path from which the assets are served:

  app.useStaticAssets(join(__dirname, '..', 'public'), {
    prefix: '/public/',
  });

In this example your path is prefixed with public (e.g. http://localhost:3000/public/example.png)

Solution 3

There are two ways to serve static content in NestJs. Either use 1 OR 2.

1.Using ServeStaticModule in app.module.ts

import { Module } from '@nestjs/common';
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';
import { mainModule } from 'process'    
@Module({
  imports: [
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, '..', 'public'),
    }),
  ],
})
export class AppModule {}

2.Using NestExpressApplication in main.ts [Even by default Nest Js uses Express only]

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,
  );

  app.useStaticAssets(join(__dirname, '..', 'public'));

  await app.listen(3000);
}
bootstrap();
Share:
13,492
Guille
Author by

Guille

Updated on June 18, 2022

Comments

  • Guille
    Guille almost 2 years

    I'm started to learning MEAN stack and when I went to Express I saw that existed a extra layer in the express framework that is called NestJS. It had all what I wanted and it had an Angular-like syntax so was perfect to me.

    But every new step is a nightmare documentation isn't usefull at all. Now I'm fighting with the framework to achieve to serve images and dont use the API for this kind of calls.

    I tried all that I found on Internet, for example:

    main.ts

    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';
    import * as bodyParser from 'body-parser';
    import * as express from 'express';
    import { join } from 'path';
    
    import { NestExpressApplication } from '@nestjs/platform-express';
    
    
    
    declare const module: any;
    
    async function bootstrap() {
      const app = await NestFactory.create<NestExpressApplication>(AppModule);
    
      app.useStaticAssets(join(__dirname, '..', 'public'));
    
    
    
    
      app.enableCors({
        origin: true,
        methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
        credentials: true,
      });
    
    //I tried this 2 options (https://docs.nestjs.com/techniques/mvc) (https://whatthecode.dev/serve-static-files-with-nest-js/)
      app.use('/resources', express.static(process.cwd() + '\\resources'));
      app.useStaticAssets(join(__dirname, '..', '\\public'));
    
      app.use(bodyParser.json({ limit: '50mb' }));
      app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
     
      //console.log(process.cwd());
    
    
      await app.listen(3000);
    
      if (module.hot) {
        module.hot.accept();
        module.hot.dispose(() => app.close());
      }
    
    }
    bootstrap();
    
    

    I tried to put it in the app.module as this (it worked but is always looking for an index.html not images):

    
    import { AnimalsModule } from './animals/animals.module';
    import { SpeciesModule } from './species/species.module';
    import { AuthModule } from './auth/auth.module';
    import { UsersModule } from './users/users.module';
    import { BreedModule } from './breed/breed.module';
    import { StateModule } from './state/state.module';
    import { PhotoModule } from './photo/photo.module';
    
    
    @Module({
      imports: [
        ServeStaticModule.forRoot({
          rootPath: join(__dirname, '..', 'public'),   // <-- path to the static files
        }),
        TypeOrmModule.forRoot({
          type: 'mysql',
          host: 'localhost',
          port: 3306,
          username: 'root',
          password: '',
          database: 'nest',
          entities: [__dirname + '/**/*.entity{.ts,.js}'],
          synchronize: true,
        }),
        AnimalsModule,
        SpeciesModule,
        BreedModule,
        StateModule,
        AuthModule,
        UsersModule,
        PhotoModule,
      ],
    })
    
    //It seems that ignores this register and just uses the method signature options
    @Module({
      imports: [MulterModule.register({
        dest: './resources/tmp',
        limits: { fieldSize: 25 * 1024 * 1024 * 1024, fileSize: 25 * 1024 * 1024 * 1024 }
      })],
      controllers: [AppController],
      providers: [AppService],
    })
    export class AppModule { }
    

    How the hell I can serve images or files and avoid the api routing?

    Thanks to all.

  • xitas
    xitas almost 3 years
    i have done that but have this error "ENOENT: no such file or directory" it is show me file not find in \dist\public\index.html
  • Dennis van de Hoef
    Dennis van de Hoef almost 3 years
    Can you please edit this and explain why? In that case this would also help other people finding this issue, as it is most likely that the original question asker already solved the issue after 10 months ;)