Skip to content

Using Services

This guide will show you how to register, configure, and create your own service. In this example we will be assuming two different Logger implementations.

  • PrintLogger: Prints logs.
  • FileLogger: Saves logs to a file. Already conforms to ServiceType.


Let's take a look at how we can register our PrintLogger. First you must conform your type to Service. The easiest way to do this is simply adding the conformance in an extension.

extension PrintLogger: Service { }

It's an empty protocol so there should be no missing requirements.


Now the service can be registered to the Services struct. This is usually done in configure.swift.

services.register(Logger.self) { container in
    return PrintLogger()

By registering the PrintLogger using a factory (closure) method, we allow the Container to dynamically create the service once it is needed. Any SubContainers created later can call this method again to create their own PrintLoggers.

Service Type

To make registering a service easier, you can conform it to ServiceType.

extension PrintLogger: ServiceType {
    /// See `ServiceType`.
    static var serviceSupports: [Any.Type] {
        return [Logger.self]

    /// See `ServiceType`.
    static func makeService(for worker: Container) throws -> PrintLogger {
        return PrintLogger()

Services conforming to ServiceType can be registered using just the type name. This will automatically conform to Service as well.



You can also register pre-initialized instances to Services.

services.register(PrintLogger(), as: Logger.self)


If using reference types (class) this method will share the same object between all Containers and SubContainers. Be careful to protect against race conditions.


If more than one service is registered for a given interface, we will need to choose which service is used.


Assuming the above services are registered, we can use service Config to pick which one we want.

switch env {
case .production: config.prefer(FileLogger.self, for: Logger.self)
default: config.prefer(PrintLogger.self, for: Logger.self)

Here we are using the Environment to dynamically prefer a service. This is usually done in configure.swift.


You can also dynamically register services based on environment instead of using service config. However, service config is required for choosing services that come from the framework or a provider.


After you have registered your services, you can use a Container to create them.

let logger = try someContainer.make(Logger.self)
logger.log("Hello, world!")

// PrintLogger or FileLogger depending on the container's environment
print(type(of: logger)) 


Usually the framework will create any required containers for you. You can use BasicContainer if you want to create one for testing.