How does tower::Layer::layer wrap services differently from ServiceBuilder::into_inner for middleware ordering?

Layer::layer wraps services by applying middleware from inside-out (the innermost service is wrapped first), while ServiceBuilder::into_inner applies middleware in the order they're added (outermost middleware processes requests first)—making the ordering reversed between the two approaches and critical to understand for correct middleware composition. The difference lies in when the wrapping occurs: Layer::layer is an imperative operation that immediately wraps a service, while ServiceBuilder is a declarative chain that builds the complete middleware stack only when into_inner or into_service is called.

Basic Layer::layer Usage

use tower::{Service, ServiceBuilder};
use tower::layer::layer_fn;
use std::task::{Context, Poll};
use pin_project_lite::pin_project;
use std::future::Future;
use std::pin::Pin;
 
// A simple middleware that logs requests
struct LoggingLayer;
 
impl<S> tower::Layer<S> for LoggingLayer {
    type Service = LoggingService<S>;
    
    fn layer(&self, inner: S) -> Self::Service {
        LoggingService { inner }
    }
}
 
struct LoggingService<S> {
    inner: S,
}
 
impl<S, Request> Service<Request> for LoggingService<S>
where
    S: Service<Request>,
{
    type Response = S::Response;
    type Error = S::Error;
    type Future = S::Future;
    
    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.inner.poll_ready(cx)
    }
    
    fn call(&mut self, req: Request) -> Self::Future {
        println!("Logging middleware: processing request");
        self.inner.call(req)
    }
}
 
// Using Layer::layer directly
fn basic_layer_usage() {
    // Start with innermost service
    let inner = MyService;
    
    // Apply layers from inside to outside
    let service = LoggingLayer.layer(inner);
    // Result: LoggingService(MyService)
}

Layer::layer immediately wraps the provided service.

Basic ServiceBuilder Usage

use tower::ServiceBuilder;
 
fn basic_service_builder() {
    // ServiceBuilder collects layers and applies them later
    let service = ServiceBuilder::new()
        .layer(LoggingLayer)
        .service(MyService);
    
    // This is equivalent to:
    // LoggingLayer.layer(MyService)
}

ServiceBuilder collects layers and applies them when service is called.

The Critical Ordering Difference

use tower::ServiceBuilder;
 
// Ordering demonstration
fn ordering_difference() {
    // Using Layer::layer directly (imperative):
    // Wrap from inside-out
    let service = AuthLayer.layer(
        RateLimitLayer.layer(
            TimeoutLayer.layer(
                MyService
            )
        )
    );
    // Order: MyService -> TimeoutLayer -> RateLimitLayer -> AuthLayer
    // Request flow: AuthLayer -> RateLimitLayer -> TimeoutLayer -> MyService
    // Response flow: MyService -> TimeoutLayer -> RateLimitLayer -> AuthLayer
    
    // Using ServiceBuilder (declarative):
    let service = ServiceBuilder::new()
        .layer(AuthLayer)
        .layer(RateLimitLayer)
        .layer(TimeoutLayer)
        .service(MyService);
    // SAME ORDER! Request flow: AuthLayer -> RateLimitLayer -> TimeoutLayer -> MyService
    // ServiceBuilder reverses the layer application internally
}

Both approaches result in the same ordering when written correctly.

Understanding the Reversal

use tower::ServiceBuilder;
 
fn understanding_reversal() {
    // When you write ServiceBuilder::new()
    //     .layer(A)
    //     .layer(B)
    //     .layer(C)
    //     .service(inner)
    //
    // Internally, it builds:
    // A.layer(B.layer(C.layer(inner)))
    //
    // So request flow is: A -> B -> C -> inner
    // And layers are applied "inside-out" but written "outside-in"
    
    // The key insight: layers are stored in order, then applied in reverse
    
    // If you were to use Layer::layer directly:
    let service = A.layer(
        B.layer(
            C.layer(inner)
        )
    );
    // Same result, but the nesting shows the actual application order
}

ServiceBuilder stores layers in order and applies them from the innermost outward.

Manual Layer Composition

use tower::Layer;
 
fn manual_composition() {
    // Manual composition shows the nesting clearly
    struct ServiceA;
    struct ServiceB;
    struct ServiceC;
    
    // If we want order: A -> B -> C -> Inner
    // We need to nest: A(B(C(Inner)))
    
    // Start with innermost
    let with_c = LayerC.layer(InnerService);
    let with_b = LayerB.layer(with_c);
    let with_a = LayerA.layer(with_b);
    
    // Result: A wraps B wraps C wraps Inner
    // Request flow: A (outermost) -> B -> C -> Inner (innermost)
}

Manual composition requires nesting from inside to outside.

ServiceBuilder as Collection

use tower::ServiceBuilder;
 
fn service_builder_collection() {
    // ServiceBuilder collects layers
    let builder = ServiceBuilder::new()
        .layer(LayerA)
        .layer(LayerB)
        .layer(LayerC);
    
    // Layers are NOT applied yet
    // They're stored in a Vec-like structure internally
    
    // .service(inner) applies all layers to inner
    let service = builder.service(InnerService);
    
    // Equivalent to:
    // LayerA.layer(LayerB.layer(LayerC.layer(InnerService)))
    
    // The builder "knows" to apply layers in reverse storage order
}

ServiceBuilder defers layer application until service is called.

into_inner vs into_service

use tower::ServiceBuilder;
 
fn into_inner_vs_service() {
    // ServiceBuilder has two main methods:
    
    // 1. into_service(inner) - creates the full service
    let service = ServiceBuilder::new()
        .layer(LayerA)
        .layer(LayerB)
        .service(InnerService);
    
    // 2. into_inner() - returns the composed layer, NOT a service
    let layer = ServiceBuilder::new()
        .layer(LayerA)
        .layer(LayerB)
        .into_inner();
    
    // into_inner() returns a Layer, not a Service
    // You then apply it to a service:
    let service = layer.layer(InnerService);
    
    // This is useful when you want to reuse a layer composition
}

into_inner returns a composed Layer; service returns a Service.

Reusing Layer Compositions

use tower::ServiceBuilder;
 
fn reusing_layers() {
    // Create a reusable layer composition
    let common_layers = ServiceBuilder::new()
        .layer(TimeoutLayer::new(Duration::from_secs(30)))
        .layer(RateLimitLayer::new(100, Duration::from_secs(1)))
        .layer(LoggingLayer)
        .into_inner();
    // This is a Layer, not a Service
    
    // Apply to multiple services
    let user_service = common_layers.layer(UserService);
    let admin_service = common_layers.layer(AdminService);
    let public_service = common_layers.layer(PublicService);
    
    // All three services have the same middleware stack
    // Request flow for all: Logging -> RateLimit -> Timeout -> InnerService
}

into_inner enables reuse of layer compositions across multiple services.

Layer Ordering Visualization

use tower::ServiceBuilder;
 
// Request flow visualization
fn visualize_ordering() {
    // Given layers A, B, C applied in order:
    let service = ServiceBuilder::new()
        .layer(LayerA)  // Applied third (outermost)
        .layer(LayerB)  // Applied second
        .layer(LayerC)  // Applied first (innermost)
        .service(InnerService);
    
    // Request processing order:
    // 1. LayerA::call (first to see request)
    // 2. LayerB::call
    // 3. LayerC::call
    // 4. InnerService::call
    
    // Response processing order (reverse):
    // 4. InnerService produces response
    // 3. LayerC processes response
    // 2. LayerB processes response
    // 1. LayerA processes response (last to see response)
    
    // This is the "onion" model - layers wrap around the inner service
}

Layers form an onion around the inner service.

Debugging Layer Order

use tower::ServiceBuilder;
 
// Helper to visualize layer application
fn debug_layer_order() {
    struct DebugLayer(&'static str);
    
    impl<S> Layer<S> for DebugLayer {
        type Service = DebugService<S>;
        fn layer(&self, inner: S) -> Self::Service {
            println!("Wrapping with {}", self.0);
            DebugService { name: self.0, inner }
        }
    }
    
    // Using Layer::layer directly:
    println!("Direct layer application:");
    let _ = DebugLayer("A").layer(
        DebugLayer("B").layer(
            DebugLayer("C").layer(InnerService)
        )
    );
    // Output:
    // Wrapping with C
    // Wrapping with B
    // Wrapping with A
    
    // Using ServiceBuilder:
    println!("ServiceBuilder:");
    let _ = ServiceBuilder::new()
        .layer(DebugLayer("A"))
        .layer(DebugLayer("B"))
        .layer(DebugLayer("C"))
        .service(InnerService);
    // Output:
    // Wrapping with C
    // Wrapping with B
    // Wrapping with A
    // SAME ORDER!
}

Both approaches apply layers in the same order internally.

Common Ordering Mistakes

use tower::ServiceBuilder;
 
fn common_mistakes() {
    // MISTAKE 1: Thinking layers are applied in written order
    // Written order: A, B, C
    // Application order: C first, then B, then A
    // Request flow: A -> B -> C -> Inner
    
    // MISTAKE 2: Confusing layer order with middleware execution order
    // Layer A is outermost, executes first on request
    // Layer C is innermost, executes last before inner service
    
    // MISTAKE 3: Using into_inner when you need a service
    let layer = ServiceBuilder::new()
        .layer(A)
        .into_inner();  // Returns Layer, not Service
    
    // You can't call this layer directly - it needs a service
    // Correct: let service = layer.layer(InnerService);
    
    // MISTAKE 4: Using service when you need a layer
    let service = ServiceBuilder::new()
        .layer(A)
        .service(InnerService);  // Returns Service
    
    // You can't apply this to another service
    // If you need to reuse, use into_inner first
}

Understanding the distinction prevents common errors.

Practical Example: API Middleware Stack

use tower::ServiceBuilder;
use std::time::Duration;
 
fn api_middleware_stack() {
    // Typical API middleware stack
    let service = ServiceBuilder::new()
        // Outermost: Global error handling
        .layer(ErrorHandlingLayer)
        // Request ID for tracing
        .layer(RequestIdLayer)
        // Auth check
        .layer(AuthLayer::new())
        // Rate limiting
        .layer(RateLimitLayer::per_second(100))
        // Request timeout
        .layer(TimeoutLayer::new(Duration::from_secs(30)))
        // Innermost: Logging
        .layer(LoggingLayer)
        // The actual service
        .service(ApiHandler);
    
    // Request flow:
    // 1. ErrorHandlingLayer catches panics
    // 2. RequestIdLayer assigns ID
    // 3. AuthLayer validates credentials
    // 4. RateLimitLayer checks quota
    // 5. TimeoutLayer enforces deadline
    // 6. LoggingLayer logs request
    // 7. ApiHandler processes
    
    // Response flow is reversed
}

ServiceBuilder makes complex middleware stacks readable.

Creating Reusable Middleware Presets

use tower::ServiceBuilder;
 
// Reusable middleware configuration
fn production_middleware() -> impl Layer<MyService> {
    ServiceBuilder::new()
        .layer(TimeoutLayer::new(Duration::from_secs(30)))
        .layer(RateLimitLayer::new(1000, Duration::from_secs(1)))
        .layer(ConcurrencyLimitLayer::new(100))
        .layer(LoggingLayer)
        .into_inner()  // Return the composed layer
}
 
fn development_middleware() -> impl Layer<MyService> {
    ServiceBuilder::new()
        .layer(LoggingLayer)  // Minimal for development
        .into_inner()
}
 
fn use_presets() {
    let prod_layer = production_middleware();
    let dev_layer = development_middleware();
    
    // Apply to different services
    let prod_service = prod_layer.layer(ProductionApiService);
    let dev_service = dev_layer.layer(DevelopmentApiService);
}

into_inner enables reusable middleware presets.

Conditional Layer Application

use tower::ServiceBuilder;
 
fn conditional_layers(enable_auth: bool, enable_rate_limit: bool) {
    // Using ServiceBuilder conditionally
    let mut builder = ServiceBuilder::new()
        .layer(TimeoutLayer::new(Duration::from_secs(30)));
    
    if enable_auth {
        builder = builder.layer(AuthLayer::new());
    }
    
    if enable_rate_limit {
        builder = builder.layer(RateLimitLayer::per_second(100));
    }
    
    builder = builder.layer(LoggingLayer);
    
    let service = builder.service(InnerService);
    
    // Alternative: Using into_inner and conditional layer
    let base_layers = ServiceBuilder::new()
        .layer(TimeoutLayer::new(Duration::from_secs(30)))
        .into_inner();
    
    let auth_layers = if enable_auth {
        ServiceBuilder::new()
            .layer(AuthLayer::new())
            .layer(base_layers)
            .into_inner()
    } else {
        base_layers
    };
    
    let service = auth_layers.layer(InnerService);
}

Both approaches support conditional middleware.

Layer Transformers

use tower::ServiceBuilder;
 
// ServiceBuilder can transform existing services
fn transform_existing_service() {
    let existing_service = MyService;
    
    // Add middleware to existing service
    let enhanced = ServiceBuilder::new()
        .layer(LoggingLayer)
        .layer(MetricsLayer)
        .service(existing_service);
    
    // Or use into_inner and apply to multiple existing services
    let middleware = ServiceBuilder::new()
        .layer(LoggingLayer)
        .layer(MetricsLayer)
        .into_inner();
    
    let service1 = middleware.layer(Service1);
    let service2 = middleware.layer(Service2);
    let service3 = middleware.layer(Service3);
}

Transform existing services or create reusable middleware.

Ordering Summary Table

use tower::{Layer, ServiceBuilder};
 
fn summary() {
    // | Approach          | Written Order | Application Order | Request Flow      |
    // |-------------------|---------------|-------------------|-------------------|
    // | Layer::layer      | A.layer(      | C first, then B,  | A -> B -> C ->    |
    // |                   |   B.layer(    | then A            | Inner             |
    // |                   |     C.layer(  |                   |                   |
    // |                   |       Inner)))|                   |                   |
    // | ServiceBuilder    | .layer(A)     | C first, then B,  | A -> B -> C ->    |
    // |                   | .layer(B)     | then A            | Inner             |
    // |                   | .layer(C)     |                   |                   |
    // |                   | .service(...) |                   |                   |
    
    // Both produce identical ordering!
    // The key is understanding that written order = outermost first
}

Both approaches produce identical middleware ordering.

Synthesis

Quick reference:

use tower::ServiceBuilder;
 
// Layer::layer: Direct, imperative wrapping
let service = LayerA.layer(
    LayerB.layer(
        LayerC.layer(InnerService)
    )
);
// Explicit nesting shows order clearly
 
// ServiceBuilder: Declarative, cleaner syntax
let service = ServiceBuilder::new()
    .layer(LayerA)
    .layer(LayerB)
    .layer(LayerC)
    .service(InnerService);
// Same order, more readable
 
// into_inner: Reusable layer composition
let layer = ServiceBuilder::new()
    .layer(LayerA)
    .layer(LayerB)
    .into_inner();  // Returns Layer, not Service
 
let service1 = layer.layer(Service1);
let service2 = layer.layer(Service2);

When to use each:

use tower::{Layer, ServiceBuilder};
 
// Use Layer::layer when:
// - Simple, single-service wrapping
// - Need explicit control over wrapping order
// - Working with a single layer
 
// Use ServiceBuilder when:
// - Multiple layers to apply
// - Need readability and maintainability
// - Want to compose layers declaratively
 
// Use into_inner when:
// - Reusing layer composition across services
// - Creating configurable middleware presets
// - Building layers dynamically

Key insight: Layer::layer and ServiceBuilder achieve identical middleware ordering—they just present different interfaces for the same underlying composition. Layer::layer is the primitive: given an inner service, it returns a wrapped service. When you nest multiple layer calls, you're building the middleware stack from inside-out (innermost service first, then wrapped by successive layers). ServiceBuilder provides a cleaner declarative API: you write layers in the order requests flow through them (outermost first), and internally it applies them correctly. The critical realization is that the "last layer written" becomes the "innermost layer" in the final stack—the first layer you see in a ServiceBuilder chain is the first layer a request encounters. into_inner returns the composed Layer itself rather than a Service, enabling reuse of the middleware configuration across multiple services. This separation of "layer composition" from "service binding" is powerful for creating shared middleware presets that can be applied consistently across an application.