Documentation

@only

Restrict the registration of controllers, services, and dependencies to specific environments.

DocumentationDependencies

The @only(...) decorator allows you to specify in which environments a component should be available.

It can be applied to controllers, services, leaf functions, middleware, hooks, and other registrable components.

from autumn import only, Environment, service

@only(Environment.LOCAL, Environment.DEVELOPMENT)
@service
class MockPaymentService:
    ...

In this example, MockPaymentService will only be registered in the LOCAL and DEVELOPMENT environments.

If the application is started in any other environment, the component will be ignored.

Supported values

The @only(...) decorator accepts both Environment enum values and strings.

@only(Environment.DEVELOPMENT)
@service
class DebugService:
    ...

Using Environment values is recommended because it is safer and helps avoid mistakes caused by typos.

Restricting controllers

If a controller is not allowed in the current environment, Autumn will not register it.

from autumn import REST, only, Environment

@only(Environment.DEVELOPMENT)
@REST(prefix = '/debug')
class DebugController:
    ...

When running in PRODUCTION:

  • the controller will not be registered;
  • its routes will not be added to the router;
  • its endpoints will not appear in the OpenAPI documentation;
  • its dependencies will not be resolved.

This is useful for debug routes, testing APIs, and internal development tools.

Restricting services and leaf functions

The decorator can also be used for dependencies.

@only(Environment.LOCAL)
@service
class MockMailService:
    ...
@only(Environment.DEVELOPMENT)
@leaf
async def mock_payment_gateway() -> PaymentGateway:
    ...

If the current environment is not included in the allowed list, the provider will not be registered in the dependency injection container.

Environment-Specific Implementations

When different implementations are enabled in different environments, use a union type in the dependency signature.

from autumn import Environment, only, service

@only(Environment.DEVELOPMENT)
@service
class MockGateway:
    def name(self) -> str:
        return 'mock'

@only(Environment.PRODUCTION)
@service
class LiveGateway:
    def name(self) -> str:
        return 'live'

@service
class CheckoutService:
    def __init__(self, gateway: MockGateway | LiveGateway):
        self.gateway = gateway

Autumn selects the dependency whose @only(...) environments match the current application environment.

If the application runs in DEVELOPMENT, MockGateway is injected. If it runs in PRODUCTION, LiveGateway is injected.

The allowed environments must not overlap. This would be ambiguous:

@only(Environment.DEVELOPMENT)
@service
class FirstGateway:
    ...

@only(Environment.DEVELOPMENT, Environment.LOCAL)
@service
class SecondGateway:
    ...

For FirstGateway | SecondGateway, Autumn will reject this during dependency validation because both implementations are available in DEVELOPMENT.

Dependency validation

Autumn validates the dependency graph during application startup.

If an active component depends on a provider that is disabled for the current environment, the application startup will fail with an error.

@only(Environment.DEVELOPMENT)
@service
class MockGateway:
    ...

@service
class PaymentService:
    def __init__(self, gateway: MockGateway):
        self.gateway = gateway

If the application is started in PRODUCTION, Autumn will detect that PaymentService requires a dependency that is unavailable in the current environment and will stop the startup process.

This behavior helps catch configuration errors before the application begins handling requests.

Autumn also checks dependency graphs for other environments and prints warnings when the current environment can start, but another environment would fail.

@only(Environment.LOCAL)
@service
class LocalGateway:
    ...

@only(Environment.PRODUCTION)
@service
class ProductionCheckoutService:
    def __init__(self, gateway: LocalGateway):
        self.gateway = gateway

If the app runs in LOCAL, it can start because ProductionCheckoutService is not active. Autumn will still warn that the PRODUCTION graph would fail because LocalGateway is not available there.

What happens when the environment does not match

The following behavior applies to components decorated with @only(...):

Component TypeBehavior
ControllerExcluded from routing and OpenAPI
ServiceNot registered in the DI container
LeafNot registered in the DI container
MiddlewareNot attached to the application
HookNot registered
ConfigurationExcluded from container initialization

If a disabled component is not referenced anywhere, the application will continue to run normally.

If an active dependency chain relies on it, startup will fail with a dependency validation error.

When to use @only

The decorator is especially useful for:

  • mock and test service implementations;
  • debug controllers;
  • local development tools;
  • internal administrative endpoints;
  • integrations available only in specific environments;
  • middleware and hooks that should not run in production.

Typically, @only(...) is used to separate production and development implementations without requiring manual code changes.