Workspaces

Nest has two modes for organizing code:

  • standard mode: useful for building individual project-focused applications that have their own dependencies and settings, and don’t need to optimize for sharing modules, or optimizing complex builds. This is the default mode.
  • monorepo mode: this mode treats code artifacts as part of a lightweight monorepo, and may be more appropriate for teams of developers and/or multi-project environments. It automates parts of the build process to make it easy to create and compose modular components, promotes code re-use, makes integration testing easier, makes it easy to share project-wide artifacts like tslint rules and other configuration policies, and is easier to use than alternatives like github submodules. Monorepo mode employs the concept of a workspace, represented in the nest-cli.json file, to coordinate the relationship between the components of the monorepo.

It’s important to note that virtually all of Nest’s features are independent of your code organization mode. The only affect of this choice is how your projects are composed and how build artifacts are generated. All other functionality, from the CLI to core modules to add-on modules work the same in either mode.

Also, you can easily switch from standard mode to monorepo mode at any time, so you can delay this decision until the benefits of one or the other approach become more clear.

Standard mode

When you run nest new, a new project is created for you using a built-in schematic. Nest does the following:

  1. Create a new folder, corresponding to the name argument you provide to nest new
  2. Populate that folder with default files corresponding to a minimal base-level Nest application. You can examine these files at the typescript-starter repository.
  3. Provide additional files such as nest-cli.json, package.json and tsconfig.json that configure and enable various tools for compiling, testing and serving your application.

From there, you can modify the starter files, add new components, add dependencies (e.g., npm install), and otherwise develop your application as covered in the rest of this documentation.

Monorepo mode

To enable monorepo mode, you start with a standard mode structure, and add projects. A project can be a full application (which you add to the workspace with the command nest generate app) or a library (which you add to the workspace with the command nest generate library). We’ll discuss the details of these specific types of project components below. The key point to note now is that it is the act of adding a project to an existing standard mode structure that converts it to monorepo mode. Let’s look at an example.

If we run:

  1. nest new my-project

We’ve constructed a standard mode structure, with a folder structure that looks like this:

src
app.controller.ts
app.service.ts
app.module.ts
main.ts
node_modules
nest-cli.json
package.json
tsconfig.json
tslint.json

We can convert this to a monorepo mode structure as follows:

  1. cd my-project
  2. nest generate app my-app

At this point, nest converts the existing structure to a monorepo mode structure. This results in a few important changes. The folder structure now looks like this:

apps
my-app
src
app.controller.ts
app.service.ts
app.module.ts
main.ts
tsconfig.app.json
my-project
src
app.controller.ts
app.service.ts
app.module.ts
main.ts
tsconfig.app.json
nest-cli.json
package.json
tsconfig.json
tslint.json

The generate app schematic has reorganized the code - moving each application project under the apps folder, and adding a project-specific tsconfig.app.json file in each project’s root folder. Our original my-project app has become the default project for the monorepo, and is now a peer with the just-added my-app, located under the apps folder. We’ll cover default projects below.

error Warning The conversion of a standard mode structure to monorepo only works for projects that have followed the canonical Nest project structure. Specifically, during conversion, the schematic attempts to relocate the src and test folders in a project folder beneath the apps folder in the root. If a project does not use this structure, the conversion will fail or produce unreliable results.

Workspace projects

A mono repo uses the concept of a workspace to manage its member entities. Workspaces are composed of projects. A project may be either:

  • an application: a full Nest application including a main.ts file to bootstrap the application. Aside from compile and build considerations, an application-type project within a workspace is functionally identical to an application within a standard mode structure.
  • a library: a library is a way of packaging a general purpose set of features (modules, providers, controllers, etc.) that can be used within other projects. A library cannot run on its own, and has no main.ts file. Read more about libraries here.

All workspaces have a default project (which should be an application-type project). This is defined by the top-level "root" property in the nest-cli.json file, which points at the root of the default project (see CLI properties below for more details). Usually, this is the standard mode application you started with, and later converted to a monorepo using nest generate app. When you follow these steps, this property is populated automatically.

Default projects are used by nest commands like nest build and nest start when a project name is not supplied.

For example, in the above monorepo structure, running

  1. $ nest start

will start up the my-project app. To start my-app, we’d use:

  1. $ nest start my-app

Applications

Application-type projects, or what we might informally refer to as just “applications”, are complete Nest applications that you can run and deploy. You generate an application-type project with nest generate app.

This command automatically generates a project skeleton, including the standard src and test folders from the typescript starter. Unlike standard mode, an application project in a monorepo does not have any of the package dependency (package.json) or other project configuration artifacts like .prettierrc and tslint.json. Instead, the monorepo-wide dependencies and config files are used.

However, the schematic does generate a project-specific tsconfig.app.json file in the root folder of the project. This config file automatically sets appropriate build options, including setting the compilation output folder properly. The file extends the top-level (monorepo) tsconfig.json file, so you can manage global settings monorepo-wide, but override them if needed at the project level.

Libraries

As mentioned, library-type projects, or simply “libraries”, are packages of Nest components that need to be composed into applications in order to run. You generate a library-type project with nest generate library. Deciding what belongs in a library is an architectural design decision. We discuss libraries in depth in the libraries chapter.

CLI properties

Nest keeps the metadata needed to organize, build and deploy both standard and monorepo structured projects in the nest-cli.json file. Nest automatically adds to and updates this file as you add projects, so you usually do not have to think about it or edit its contents. However, there are some settings you may want to change manually, so it’s helpful to have an overview understanding of the file.

After running the steps above to create a monorepo, our nest-cli.json file looks like this:

  1. {
  2. "collection": "@nestjs/schematics",
  3. "sourceRoot": "apps/my-project/src",
  4. "monorepo": true,
  5. "root": "apps/my-project",
  6. "compilerOptions": {
  7. "webpack": true,
  8. "tsConfigPath": "apps/my-project/tsconfig.app.json"
  9. },
  10. "projects": {
  11. "my-project": {
  12. "type": "application",
  13. "root": "apps/my-project",
  14. "entryFile": "main",
  15. "sourceRoot": "apps/my-project/src",
  16. "compilerOptions": {
  17. "tsConfigPath": "apps/my-project/tsconfig.app.json"
  18. }
  19. },
  20. "my-app": {
  21. "type": "application",
  22. "root": "apps/my-app",
  23. "entryFile": "main",
  24. "sourceRoot": "apps/my-app/src",
  25. "compilerOptions": {
  26. "tsConfigPath": "apps/my-app/tsconfig.app.json"
  27. }
  28. }
  29. }
  30. }

The file is divided into sections:

  • a global section with top-level properties controlling standard and monorepo-wide settings
  • a top level property ("projects") with metadata about each project. This section is present only for monorepo-mode structures.

The top-level properties are as follows:

  • "collection": points at the collection of schematics used to generate components; you generally should not change this value
  • "sourceRoot": points at the root of the source code for the single project in standard mode structures, or the default project in monorepo mode structures
  • "compilerOptions": a map with keys specifying compiler options and values specifying the option setting; see details below
  • "monorepo": (monorepo only) for a monorepo mode structure, this value is always true
  • "root": (monorepo only) points at the project root of the default project

Global compiler options

These properties specify the compiler to use as well as various options that affect any compilation step, whether as part of nest build or nest start, and regardless of the compiler, whether tsc or webpack.

Property Name Property Value Type Description
webpack boolean If true, use webpack compiler. If false or not present, use tsc. In monorepo mode, the default is true (use webpack), in standard mode, the default is false (use tsc). See below for details.
tsConfigPath string (monorepo only) Points at the file containing the tsconfig.json settings that will be used when nest build or nest start is called without a project option (e.g., when the default project is built or started).
webpackConfigPath string Points at a webpack options file. If not specified, Nest looks for the file webpack.config.js. See below for more details.
deleteOutDir boolean If true, whenever the compiler is invoked, it will first remove the compilation output directory (as configured in tsconfig.json, where the default is ./dist).
assets array Enables automatically distributing non-TypeScript assets whenever a compilation step begins (asset distribution does not happen on incremental compiles in --watch mode). See below for details.

Specified compiler

The reason for the different default compilers is that for larger projects (e.g., more typical in a monorepo) webpack can have significant advantages in build times and in producing a single file bundling all project components together. If you wish to generate individual files, set "webpack" to false, which will cause the build process to use tsc.

Webpack options

The webpack options file can contain standard webpack configuration options. For example, to tell webpack to bundle node_modules (which are excluded by default), add the following to webpack.config.js:

  1. module.exports = {
  2. externals: [],
  3. };

Since the webpack config file is a JavaScript file, you can even expose a function that takes default options and returns a modified object:

  1. module.exports = function(options) {
  2. return {
  3. ...options,
  4. externals: [],
  5. };
  6. }

Assets

TypeScript compilation automatically distributes compiler output (.js and .d.ts files) to the specified output directory. It can also be convenient to distribute non-TypeScript files, such as .graphql files, images, .html files and other assets. This allows you to treat nest build (and any initial compilation step) as a lightweight development build step, where you may be editing non-TypeScript files and iteratively compiling and testing.

The value of the assets key should be an array of elements specifying the files to be distributed. The elements can be simple strings with glob-like file specs, for example:

  1. "assets": ["**/*.graphql"]

For finer control, the elements can be objects with the following keys:

  • "include": glob-like file specifications for the assets to be distributed
  • "exclude": glob-like file specifications for assets to be excluded from the include list
  • "outDir": a string specifying the path (relative to the root folder) where the assets should be distributed. Defaults to the same output directory configured for compiler output.

For example:

  1. "assets": [
  2. { "include": "**/*.graphql", "exclude": "**/omitted.graphql" },
  3. ]

Project properties

This element exists only for monorepo-mode structures. You generally should not edit these properties, as they are used by Nest to locate projects and their configuration options within the monorepo.