# Injection scopes

The scope of a Providers defines the lifecycle and visibility of that bean in the contexts in which it's used.

Ts.ED DI define 3 types of : singleton, request and instance which can be used on Provider, Service, Middleware and Controller.

# Singleton scope

Singleton scope is the default behavior of all providers. That means all providers are create on the server initialization.

import {Controller, Get, ProviderScope, Scope} from "@tsed/common";

@Controller("/")
@Scope(ProviderScope.SINGLETON)  // OPTIONAL, leaving this annotation a the same behavior
export class MyController {
  private rand = Math.random() * 100;

  @Get("/random")
  async getValue() {
    return this.rand;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

Note

In this example all request on /random endpoint return the same random value.

# Request scope

Request scope will create a new instance of provider for each incoming request. A new container will be created and attached to the request. It'll contains all provider annotated by @Scope(ProviderScope.REQUEST).

import {Controller, Get, ProviderScope, Scope} from "@tsed/common";

@Controller("/")
@Scope(ProviderScope.SINGLETON)  // OPTIONAL, leaving this annotation a the same behavior
export class MyController {
  private rand = Math.random() * 100;

  @Get("/random")
  async getValue() {
    return this.rand;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

Each request on /random will return a different random value.

# Chain with Service

It also possible to use @Scope(ProviderScope.REQUEST) on service if your service is injected on a controller which is annotated by @Scope(ProviderScope.REQUEST) too.

Here a working example:

import {Controller, Get, ProviderScope, Scope, Service} from "@tsed/common";

@Service()
@Scope(ProviderScope.REQUEST)
export class MyService {
  public rand = Math.random() * 100;
}

@Controller("/")
@Scope(ProviderScope.REQUEST)
export class MyController {
  constructor(private myService: MyService) {
  }

  @Get("/random")
  async getValue() {
    return this.myService.rand;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

And here an unworking example:

import {Controller, Get, ProviderScope, Scope, Service} from "@tsed/common";

@Service()
@Scope(ProviderScope.REQUEST)
export class MyService {
  public rand = Math.random() * 100;
}

@Controller("/")
@Scope(ProviderScope.SINGLETON) // SINGLETON avoid all Scope("request") annotation
export class MyController {
  constructor(private myService: MyService) {
  }

  @Get("/random")
  async getValue() {
    return this.myService.rand;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

WARNING

The SINGLETON annotation avoid the @Scope(ProviderScope.REQUEST) annotation put on MyService.

WARNING

The @Scope(ProviderScope.REQUEST) annotation has no effect on Global middlewares.

# Performance

Using request-scoped providers will obviously affect application performance. Even though Ts.ED is trying to cache as much metadata as possible, it will still have to create an instance of your class on each request. Hence, it will slow down your average response time and overall benchmarking result. If your provider doesn't necessarily need to be request-scoped, you should rather stick with the singleton scope.

# Instance scope

Instance scope use on provider tell the injector to create a new instance each time the provider is injected to another one.

import {Controller, Get, ProviderScope, Scope, Service} from "@tsed/common";

@Service()
@Scope(ProviderScope.INSTANCE)  // OPTIONAL, leaving this annotation a the same behavior
export class MyInstanceService {
  private rand = Math.random() * 100;

  @Get("/random")
  async getValue() {
    return this.rand;
  }
}

@Controller("/")
@Scope(ProviderScope.SINGLETON)  // OPTIONAL, leaving this annotation a the same behavior
export class MyController {
  constructor(instance1: MyInstanceService, instance2: MyInstanceService) {
    console.log("IsSame", instance1 === instance2);
    console.log("instance1", instance1.getValue());
    console.log("instance2", instance2.getValue());
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22