What lifetime should you register a repository, a service, and a cache?

ASP.NET Core Dependency Injection Intermediate 2–3 Yrs3–5 Yrs Architecture 1 min read

Quick Answer

Repository / unit-of-work / anything touching DbContext → Scoped (matches the request-scoped context). Stateless domain/application services → Scoped by default (or Transient if truly stateless and cheap). Cache, clock, configuration, HttpClient factory internals → Singleton (thread-safe, app-wide).

Anything that touches the DbContext — repositories, the unit of work — is scoped, because the context itself is scoped per request and everything in that request should share it. My stateless application services I also register as scoped by default; transient is only for genuinely trivial stateless helpers. Singletons are for things that are shared across the whole app and are safe to share: a memory cache, a clock, configuration. And the rule that a singleton can only inject other singletons always applies.

  • Scoped is the safe default in a web app — it lines up with the request and with EF Core.
  • Transient is fine for lightweight stateless helpers; avoid it for anything holding a connection or that's expensive to build.
  • Singleton for shared state that's safe to share — but it must be thread-safe and it can only depend on other singletons.
  • An in-memory cache is a singleton; a per-request cache of computed values is scoped.