1. Overview

The Swagger user interface allows us to view information about our REST services. This can be very convenient for development. However, owing to security concerns, we might not want to allow this behavior in our public environments.

In this short tutorial, we’ll look at how to turn Swagger off in production.

2. Swagger Configuration

To set up Swagger using SpringDoc, we define it in a configuration bean.

Let’s create a SwaggerConfig class:

public class SwaggerConfig {
    public OpenAPI openAPI() {
        return new OpenAPI().info(new Info().title("SpringDoc Disable SwaggerUI example")
            .description("SpringDoc Disable SwaggerUI application")

By default, this configuration bean is always injected into our Spring context. Thus, Swagger becomes available for all environments.

To disable Swagger in production, let’s toggle whether this configuration bean is injected.

3. Using Spring Profiles

In Spring, we can use the @Profile annotation to enable or disable the injection of beans.

Let’s try using a SpEL expression to match the “swagger” profile, but not the “prod” profile:

@Profile({"!prod && swagger"})

This forces us to be explicit about environments where we want to activate Swagger. It also helps to prevent accidentally turning it on in production.

We can add the annotation to our configuration:

@Profile({"!prod && swagger"})
public class SwaggerConfig {

Now, let’s test that it works, by launching our application with different settings for the spring.profiles.active property:

-Dspring.profiles.active=prod // Swagger is disabled

-Dspring.profiles.active=prod,anyOther // Swagger is disabled

-Dspring.profiles.active=swagger // Swagger is enabled

-Dspring.profiles.active=swagger,anyOtherNotProd // Swagger is enabled

none // Swagger is disabled

4. Using Conditionals

Spring Profiles can be too coarse-grained a solution for feature toggles. This approach can lead to configuration errors and lengthy, unmanageable lists of profiles.

As an alternative, we can use @ConditionalOnExpression, which allows specifying custom properties for enabling a bean:

@ConditionalOnExpression(value = "${useSwagger:false}")
public class SwaggerConfig {

If the “useSwagger” property is missing, the default here is false.

To test this, we can either set the property in the application.properties (or application.yaml) file or set it as a VM option:


We should note that this example does not include any way of guaranteeing that our production instance cannot accidentally have useSwagger set to true.

5. Avoiding Pitfalls

If enabling Swagger is a security concern, then we need to choose a strategy that’s mistake-proof, but easy to use.

Some SpEL expressions can work against these aims when we use @Profile:

@Profile({"!prod"}) // Leaves Swagger enabled by default with no way to disable it in other profiles
@Profile({"swagger"}) // Allows activating Swagger in prod as well
@Profile({"!prod", "swagger"}) // Equivalent to {"!prod || swagger"} so it's worse than {"!prod"} as it provides a way to activate Swagger in prod too

This is why our @Profile example used:

@Profile({"!prod && swagger"})

This solution is probably the most rigorous, as it makes Swagger disabled by default and guarantees it cannot be enabled in “prod”.

6. Conclusion

In this article, we looked at solutions for disabling Swagger in production.

We looked at how to toggle the bean that turns Swagger on, via the @Profile and @ConditionalOnExpression annotations. We also considered how to protect against misconfiguration and undesirable defaults.

As always, the example code from this article can be found on GitHub.