NestJS is solving the issue of backend architecture. Add to that the popular choice of React on the frontend and you’ll find that full-stack JS is in a really good place right now. Can we combine these into an easy-to-use MVC architecture to enable quick prototyping?
TLDR; Yes! In the nestjs-starter repo, I’m combining NestJS and Next.js, connected with GraphQL, in Typescript (end-to-end typing, of course!), in a single MVC repo (not a monorepo of multiple projects), with some added functionality such as authentication via Passport and Cognito.
This article covers NestJS + Next.js integration.
Why a single MVC repo? Lightweight infrastructure! 1 repo, 1 deployment, no synchronization needed. The same backend that serves the API can serve the frontend too. Of course, backend and frontend code and config need to be well-separated within the repo, and separable into their own repos in the future when needed. Typescript and ESLint provide great support for this.
Why Next.js? It’s the leading React framework. Much easier configuration than with create-react-app. Options for CSR, SSR, and static pages. SSR in particular is great with a Nest API on the same host. (There are resources out there for integrating Nest with CRA and plain React too.)
Frontend-first or backend-first? You can choose to host Nest via Next or Next via Nest (I know, these names...). If you have a Nest deployment you can use it as a custom server for Next. Note although that “A custom server will remove important performance optimizations, like serverless functions and Automatic Static Optimization.” On the other hand, if you have a Next deployment you can use serverless functions and dynamic API routes to run Nest. This might restrict scalability, hosting options, and the overall structure of a Nest app. So in this example, I decided to host a Nest app and serve Next through that. (Here’s an attempt the other way around.)
With all that said, only the implementation is left.
A quick search gets us nest-next, but if you ended up here you might’ve had issues like me (1, 2) or found that it doesn’t solve well the separation of backend and frontend: forced
pages folder location on the top of the structure, or their custom
tsconfigsetup. You’ll find that you can solve separation by specifying any folder you prefer, and the code to serve the Next app is simple enough that you don’t have to hide it in a complex and opinionated library.
Other attempts include:
- 1, this article with missing code examples
- 2, this promising solution, that ends up overwriting the
- 3, this video with the related repo explaining an older version of
- 4, this lesser-known but great solution and the related library, that once again hides something fairly simple into an opinionated library
My solution below combines 2 and 4. Instead of a library, I use an explicit 15-line service fully under my control.
Step 1, Install
Step 2, View module
As you see in the view service we explicitly create a Next.js server. You can supply your custom config and directory. I chose to have
src/server folders. Your Next pages will then be in
You’ll also notice the 2 specific routes in the controller,
@Get('home')for a single page and
@Get('_next*')for assets. Defining a catch-all route currently overwrites the
/graphql endpoint regardless of the order of imports in your main module. If you’re using that, you’ll need to define pages explicitly. The handler for the pages will be the same.
You can use Guards as well, e.g. to manage authentication from Nest.
Step 3, Next page 🎉
You can also make use of SSR with Next’s
getServerSidePropsto query your API.
Step 4, Folder structure
Move server code to
src/serverand add further config to make the folder structure work:
Step 5, Integration tests (optional)
If you’re running integration tests on your app module, importing
ViewModule there will make the tests fail. I created a top-level
ServerModule to combine
ViewModule as the entry module: https://github.com/thisismydesign/nestjs-starter/pull/2/commits/aff04b4a537afb6d3bb4f3a4d6af6e7d867e8a84
Finally, you have a deployment-ready app to quickly build backend and frontend together. You’ll find more examples for pages, querying data from the backend, and other features in the repo: https://github.com/thisismydesign/nestjs-starter