Nest: Add documentation on how to serve static files

Created on 7 Feb 2018  路  23Comments  路  Source: nestjs/nest

I'm submitting a...


[ ] Regression 
[ ] Bug report
[ ] Feature request
[x] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

The documentation is very well written and very useful; however I think an example of serving a static file would be a huge plus.

I'm trying to serve an Angular App bundled with a NestJS backend, and see no clear way to do that. An example serving a static html file would help a lot.

question 馃檶

Most helpful comment

Hello, I am new to Nest, but I think that you are looking to serve a SPA application (Angular or similar). I am setting up something similar with this example:
https://docs.nestjs.com/recipes/serve-static

All 23 comments

Hi @testos944,
Actually, it's in the docs already, take a look here: https://docs.nestjs.com/techniques/mvc. Let me know if you would have any questions 馃檪

Well, not if you don't want to use a view engine but serve only a plain html file :)

But I guess I can juste use res.sendfile('public/index.html'), I will try this out.

Yes, that's true. I'll provide a small example without any engine soon 馃檪

For anyone wondering :

import * as express from 'express';
app.use(express.static(path.join(__dirname, 'public')));

If you put your index.html file in the public folder, it should be good to go

@kamilmysliwiec, is there any way to have a global catch all route ? I want to catch all routes (except those defined in my modules/controllers), something like that in expressjs:

app.get('*', function(req, res){
  res.redirect('/');
});

If you're interested in serving static files, here's a nice way to do it with fastify and fastify-static. This solution assumes that your static files are in the root of the project, in the folder _dist/public_. Then, add the following lines to:

_main.ts_

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

  app.useStaticAssets({
    root: path.resolve(__dirname + "../dist/public")
  });
...
}

_app.controller.ts_

  @Get()
  root(@Res() res) {
    res.sendFile("index.html");
  }

This will serve your main _index.html_ as well as any other assets on the root path "/".

@kamilmysliwiec if you're still working on examples I would love to see an example where nestjs serves both static files and json responses depending on the route. I would love to serve both my react app and the json needed from the server!

@Cspeisman here is an example (in src/main.ts)

import { join } from 'path'
import { renderFile } from 'ejs'
import { NestFactory } from '@nestjs/core'
import { AppModule } from './app.module'

(async () => {

  const app = await NestFactory.create(AppModule)

  app.
    engine('html', renderFile).
    setBaseViewsDir(join(__dirname, '../views')).
    useStaticAssets(join(__dirname, '../views/public'), {
      index: false,
      redirect: false
    })

  await app.listen(process.env.PORT || 3000)

})()

and in app.controller you render the file like so:

import { Get, Controller, Render } from '@nestjs/common'
import { AppService } from './app.service'

@Controller()
export class AppController {

  constructor(private readonly appService: AppService) { }

  @Get()
  @Render('public/index.html')
  root(): Promise<object> {
    return this.appService.root()
  }

}

@ovidiup13 Your solution is great, works on dev mode, (localhost:8080), but does not when I need to run it on a aws server.

I have checked everthing: port, firewall and others, but nestjs does not load an index.html file

@calebeaires hmm... That's weird. It depends on how you configured to access the service on aws. Have you tried with other routes to return, for example, JSON?

@Cspeisman
it is my first time leaving a question so, let me explain:
I recently started to work with Nest framewor, Until now I have couldn't do a good render. I have this:

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

app.
engine('html', renderFile).
setBaseViewsDir(join(__dirname, '../views')).
useStaticAssets(join(__dirname, '../views/public'), {
index: false,
redirect: false,
});
await app.listen(3000);
}

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

@Get()
@Render('public/clients1.html')
root() {
return this.appService.root();
}
}

export class AppService {
root() {
}
}

What should go in appService?

@Cspeisman object with all the data you want to put into the view using ejs template rendering.
if u not want to render any data u not need to return anything in the controller, i think.

This answer explains how by using an exception filter, a wild card can be achieved: https://stackoverflow.com/questions/49879274/nestjs-default-wildcard-route/49917487#49917487

If you're interested in serving static files, here's a nice way to do it with fastify and fastify-static. This solution assumes that your static files are in the root of the project, in the folder _dist/public_. Then, add the following lines to:

_main.ts_

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

  app.useStaticAssets({
    root: path.resolve(__dirname + "../dist/public")
  });
...
}

_app.controller.ts_

  @Get()
  root(@Res() res) {
    res.sendFile("index.html");
  }

This will serve your main _index.html_ as well as any other assets on the root path "/".

And if you create an ExeptionFilter and add it to the app.module.ts all paths will return index.html. You just need to take care of the routing on the client(React, Angular, etc)

`import {ArgumentsHost, Catch, ExceptionFilter, NotFoundException} from "@nestjs/common";
@Catch(NotFoundException)
export class NotFoundExceptionFilter implements ExceptionFilter {

catch(exception: any, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    response.sendFile("index.html");
}

}`

Edit: As you can find in the comment below for Nest 6 and newer HTTP_SERVER_REF is no longer exported. Solution: https://github.com/nestjs/nest/issues/402#issuecomment-485421646

I recently came to the same situation where I needed to serve an SPA (React) from within a NestJS application that also served an express legacy application.

But I did not wanted to loose the 404 on false API requests, luckily all my API requests were prefixed with api. Therefore I extended rilexus solution:

redirect-client.filter.ts

import {ArgumentsHost, Catch, HttpServer, Inject, NotFoundException} from '@nestjs/common';
import {BaseExceptionFilter, HTTP_SERVER_REF} from '@nestjs/core';
import {resolve} from 'path';

@Catch(NotFoundException)
export class AllExceptionsFilter extends BaseExceptionFilter {
    constructor(@Inject(HTTP_SERVER_REF) applicationRef: HttpServer) {
        super(applicationRef);
    }

    catch(exception: any, host: ArgumentsHost) {
        const ctx = host.switchToHttp();
        const response = ctx.getResponse();
        const req = ctx.getRequest();

        if (req.path && req.path.startsWith('/api')) {
            // API 404, serve default nest 404:
            super.catch(exception, host);
        } else {
            // client access, let the SPA handle:
            response.sendFile(resolve(__dirname, '../../client/build/index.html'));
        }
    }
}

main.ts

async function bootstrap() {

    const app = await NestFactory.create(AppModule);

    app.useStaticAssets(join(__dirname, '../../client/build/'));

    const httpRef = app.get(HTTP_SERVER_REF);
    app.useGlobalFilters(new AllExceptionsFilter(httpRef));
    ...
}

@CanKattwinkel I really want to use your example but nestjs/core "has no exported member 'HTTP_SERVER_REF'.

Do you have a solution for this?

Nest.js version: 6.1.1

@jesben I think that got changed from v5 to v6. I guess we should mention that in the docs

const app = await NestFactory.create(AppModule);
const refHost = app.get(HttpAdapterHost);
const httpServer = refHost.httpAdapter.getHttpServer();

Related
- docs
- @nestjs/terminus production code

what is the Typescript Type of res (where to import Response from) in :

  @Get('*')
  public reactApp(@Res() res: Response): any {
    res.sendFile('index.html');
  }

what is the Typescript Type of res (where to import Response from) in :

  @Get('*')
  public reactApp(@Res() res: Response): any {
    res.sendFile('index.html');
  }

import { Response } from 'express';

Hello, I am new to Nest, but I think that you are looking to serve a SPA application (Angular or similar). I am setting up something similar with this example:
https://docs.nestjs.com/recipes/serve-static

Hello, i want to share images but the router redirect me everytime on an index file :'(

@Module({
imports: [
    PrismaModule,
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, '..', 'public'),
      serveStaticOptions: {
        index: false,
      },
    }),
]

If you have any suggestions :)

@ncbtart You could use app.useStaticAssets and NestFastifyApplication if it's possible. That helped me to serve my static assets, stylings, images and js files

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

yanshuf0 picture yanshuf0  路  3Comments

janckerchen picture janckerchen  路  3Comments

artaommahe picture artaommahe  路  3Comments

marshall007 picture marshall007  路  3Comments

cojack picture cojack  路  3Comments