Skip to main content
The @talosjs/service component is the service layer foundation for Talos applications. A service is an injectable unit of business logic, such as order processing, payment handling, or email dispatch, that you register with a decorator and resolve from the container. Each service implements the IService interface, exposing a single execute(data?) entry point, and is wired into @talosjs/container so dependencies resolve on their own.

What a service is for

Services hold the domain operations that you’d otherwise scatter through controllers and routes, which keeps controllers thin and delegating. Register one with @decorator.service() and resolve it anywhere with container.get(), with no manual wiring. Because every service implements IService, they share the same execute(data?) shape and compose predictably, with one service resolving and calling another to build a larger operation from smaller units. Each service picks its own scope, singleton, transient, or request, to match its lifecycle.

How it works

A service is a plain class decorated with @decorator.service(). The decorator calls container.add(target, scope), registering the class with @talosjs/container. From then on, container.get(MyService) returns an instance with its scope honored: the container constructs it, caches it (for singletons), and resolves any container-backed dependencies it pulls in. The IService contract is intentionally minimal:
The decorator defaults to the singleton scope, but accepts any EContainerScope:

Decorator and usage

@decorator.service(scope?)

Registers a service class with the container. It takes an optional scope (defaults to EContainerScope.Singleton) and returns a class decorator that adds the target to the container.
Resolve it from the container wherever you need it; the decorator already registered it:
Pass a scope to change the lifecycle, for example a fresh instance per resolution:
Services compose by resolving one another from the container, letting a higher-level operation orchestrate smaller services:

Designing services

Give each service a single business operation, and compose services rather than letting one grow into a god class. Keep execute() as the public entry point: put the orchestration there and break the steps into private methods. Replace the default Record<string, unknown> data shape with a precise interface for the service’s input, and since data is optional, guard for undefined before you use it. Get services from the container with container.get() so scopes and dependencies are honored, and avoid new. Default to singleton scope for stateless logic, reaching for transient or request scope only when per-call or per-request state actually matters. Keep routing and HTTP concerns in controllers and let the services do the work.

CLI command

Scaffold a service class and its test file with the generator. It writes the class under modules/<module>/src/services/<Name>Service.ts, adds a matching test, and installs @talosjs/service if it is missing.
The generated class is a ready-to-fill IService stub:
See service:create for the full command reference.

Use with Claude and Codex

The generator ships a matching service:create skill. It runs the scaffold, then guides your AI agent through completing the service: defining a real ServiceDataType, implementing execute() with the business logic, and injecting dependencies. Initialize the skills once for your agent.
Then ask Claude in natural language. It maps the request to the generator, runs it, and fills in the implementation:
Prompt
For example, the prompt above maps to service:create --name=Invoice, then implements execute() to compute the totals.