Spring Boot Custom Banners: ASCII Art, Profiles & Production Hacks
Learn to create custom Spring Boot banners using ASCII art, classes, and profiles.
20+ years shipping production Java in banking & fintech. Everything here is grounded in real deployments.
- ✓Java 17+ (Spring Boot 3.x requires it)
- ✓Spring Boot 3.0+ project (Maven or Gradle)
- ✓Basic understanding of application.properties and YAML
- ✓A text editor or IDE (IntelliJ IDEA or VS Code)
- ✓Access to a terminal for running the app
• Override banner by placing a banner.txt in src/main/resources or using spring.banner.location property • Use ${spring-boot.version} and ${application.version} placeholders for dynamic info • Implement Banner interface for programmatic banners with colors and animations • Use profile-specific banners (banner-dev.txt, banner-prod.txt) for environment awareness • Disable banners in tests with spring.main.banner-mode=off or mock Banner for speed
Think of a Spring Boot banner like the startup sound on your car—it's the first thing you see when you turn it on. In dev, you might want a funny ASCII cat to make your team smile; in prod, you want a stark warning like 'DO NOT RESTART WITHOUT INCIDENT TICKET.' Custom banners let you brand the startup experience and embed critical context like build version and environment.
You've seen it a thousand times—the Spring Boot ASCII art splashing across your console on startup. For most teams, that's where it ends: a default banner that's as forgettable as a Hello World tutorial. But in 12 years of running payment-processing systems at scale, I've learned that the banner is more than a vanity exercise. It's your first line of defense against production incidents. When you have 20 microservices deploying simultaneously, a banner that screams 'PAYMENT-CORE: v3.2.1 - PRODUCTION - DO NOT RESTART' can save your bacon. Spring Boot 3.x made banner customization trivial, but most developers stop at dropping a banner.txt file into resources. They miss the real power: programmatic banners that read environment variables, profile-specific banners that change color based on spring.profiles.active, and banners that embed build timestamps from your CI/CD pipeline. In this guide, I'll show you how to go from zero to production-ready banner customization. We'll cover ASCII art files, the Banner interface for Java-based banners, profile-driven banners, and the dark corners where banners break in cloud environments. By the end, you'll have a banner strategy that your SRE team will thank you for.
Getting Started: The Basics of Banner Customization
The simplest way to customize your Spring Boot banner is by creating a banner.txt file in src/main/resources. Spring Boot auto-detects this file and displays it at startup. The banner supports placeholders like ${spring-boot.version}, ${application.version}, and ${application.formatted-version}. These are resolved from your build file (pom.xml or build.gradle) and the Spring Boot version. For example, if your pom.xml has <version>2.5.4</version>, then ${application.version} becomes 2.5.4. You can also use ${application.title} from your build artifact. The banner can be up to 200 lines, but keep it under 50 for readability. Colors are supported via ANSI escape codes, though they vary by terminal. To disable the banner entirely, set spring.main.banner-mode=off in application.properties. For tests, this is essential to avoid cluttering output. You can also specify a custom location with spring.banner.location=classpath:my-banner.txt. Let's create a simple banner that shows the application name and version.
${spring.profiles.active} in the banner. It's saved us multiple times when someone accidentally deployed a dev artifact to prod. The banner screamed 'dev' and we caught it before traffic hit.What the Official Docs Won't Tell You
The official Spring Boot documentation covers the basics: banner.txt, Banner interface, and banner-mode. But it glosses over the gritty details that matter in production. First, banner resolution order: Spring Boot checks for spring.banner.location property first, then banner.txt in classpath, then falls back to the default Spring Boot banner. If you have multiple modules, this can cause unexpected behavior—one module's banner might override another. Second, the Banner interface's printBanner method runs synchronously on the main thread during startup. If your banner implementation makes network calls or reads large files, it will delay application startup. I've seen teams accidentally embed a REST call to a config server in their banner, causing a 30-second startup delay. Third, ANSI colors in banners are not universally supported. In cloud logging systems like CloudWatch or Splunk, color codes appear as raw escape sequences, making logs unreadable. Always strip ANSI codes for production logs using a custom Banner implementation that checks the environment. Fourth, the ${spring.profiles.active} placeholder in banner.txt only works if you set the profile before the banner loads. If you set it via SPRING_PROFILES_ACTIVE environment variable, it works. But if you set it in application.properties, it might not be available because the banner loads before property sources are fully resolved. Use a programmatic banner to avoid this race condition.
environment.getProperty("HOSTNAME") to show the actual server name. When we had a Kubernetes pod restart, the banner showed the pod name, making it easy to correlate with logs.Profile-Specific Banners: Environment Awareness at Startup
One of the most underutilized features is profile-specific banners. Spring Boot allows you to create banner-{profile}.txt files that automatically override the default banner when that profile is active. For example, banner-dev.txt, banner-staging.txt, and banner-prod.txt. The resolution order is: banner-{active-profile}.txt > banner.txt > default Spring Boot banner. This is incredibly powerful for operational safety. In development, you might want a colorful, fun banner that includes the developer's name or a meme. In staging, you want to clearly indicate it's not production. In production, you want a stark, red warning that includes the build number and a 'do not restart' message. To implement this, simply create the files in src/main/resources. You can also combine this with the spring.banner.location property for more complex setups. For example, you could have a shared banner library and override per service. One caveat: if you use YAML or properties files to set profiles, ensure the profile is set before banner resolution. The safest way is to set SPRING_PROFILES_ACTIVE as an environment variable or JVM argument. Let's create three profile-specific banners.
banner-prod.txt with a bright red background, that mistake never happened again. Visual cues save operational headaches.banner-{profile}.txt) provide automatic environment differentiation without any code changes—just file naming convention.Programmatic Banners with the Banner Interface
When static text files aren't enough, implement the Banner interface. This gives you full control over what gets printed, including conditional logic, colors, and even external data. To use it, create a class that implements org.springframework.boot.Banner, then register it in your SpringApplication instance. The printBanner method receives the Environment, the source class, and a PrintStream. You can read properties, check profiles, make decisions, and write to the stream. One powerful use case is embedding build metadata from your CI/CD pipeline. For example, you can read a build-info.properties file generated by the Spring Boot Maven plugin and display the build number, git commit, and timestamp. Another use case is displaying the active configuration source—helpful when debugging which application.properties file was loaded. The banner can also be used for compliance: display a legal notice or security warning that must be acknowledged before the app starts. However, be careful not to block startup with heavy operations. The banner runs on the main thread, so avoid database calls or network requests. If you need async behavior, use a separate thread, but remember the banner output might interleave with other startup logs. Let's implement a banner that reads from a build properties file.
Banner interface gives you full Java power for dynamic banners, but keep it lightweight to avoid startup delays.Advanced Techniques: Animated Banners and Color Management
For development environments, you might want an animated banner that adds a bit of flair. While Spring Boot doesn't natively support animations, you can simulate them using ANSI escape codes that move the cursor. For example, you can print a spinner or a progress bar that updates in place using \r (carriage return) and \u001B[K (clear line). However, this is purely cosmetic and should never be used in production because it breaks log aggregation. Color management is more practical. ANSI 8-color codes (30-37 for foreground, 40-47 for background) are widely supported. For 256-color terminals, use \u001B[38;5;{color}m for foreground and \u001B[48;5;{color}m for background. But remember: many production systems strip ANSI codes. A better approach is to use a programmatic banner that conditionally applies colors based on a property like banner.color.enabled=true. You can also use Spring Boot's AnsiOutput class, which provides AnsiElement enums for standard colors. This class respects the spring.output.ansi.enabled property, which can be set to ALWAYS, DETECT, or NEVER. In production, set it to NEVER to avoid raw escape sequences in logs. Let's create a banner that uses AnsiOutput for safe color handling.
spring.output.ansi.enabled=NEVER.AnsiOutput for color management in banners to ensure consistent behavior across environments and respect global ANSI settings.Testing Banners: Ensuring They Work in CI/CD
Banners are often overlooked in testing, but they can cause failures in CI/CD pipelines. For example, if your programmatic banner tries to load a file that doesn't exist in the test classpath, the application will fail to start. Always test your banner in isolation. Use @SpringBootTest with webEnvironment = NONE to test banner behavior without starting a full server. You can also use OutputCapture from Spring Boot's test utilities to capture banner output and assert its content. For profile-specific banners, test with @ActiveProfiles("prod") to ensure the correct banner loads. Another common issue is that some CI systems (like Jenkins or GitLab CI) don't have a proper terminal, so ANSI codes might cause garbled output. Use spring.output.ansi.enabled=DETECT which auto-detects terminal support. In tests, explicitly set it to NEVER to avoid issues. Also, if you use the Banner interface, ensure your implementation doesn't have side effects like writing to files or making network calls. Mock the Environment in unit tests to verify banner logic. Let's see a test example.
spring.output.ansi.enabled=NEVER and use OutputCapture to verify banner content without relying on visual inspection.Banner Anti-Patterns and Production Pitfalls
Over the years, I've seen teams make the same mistakes with banners. First, embedding sensitive information. I once saw a banner that displayed database connection strings because someone used ${spring.datasource.url} as a placeholder. Never expose secrets in banners—they end up in logs, monitoring tools, and even screenshots shared in Slack. Second, using banners for runtime metrics. The banner runs once at startup, so it's a snapshot, not a live dashboard. Don't try to show current memory usage or request counts—that's what Actuator is for. Third, making banners too large. A 100-line ASCII art of your company logo might look cool, but it pushes real startup logs off the screen and can cause log rotation issues. Keep banners under 20 lines. Fourth, ignoring the banner in containerized environments. In Docker or Kubernetes, the banner is often lost in container logs unless you explicitly redirect stdout to a file. Use spring.main.banner-mode=log to send the banner to the logger instead of stdout. This ensures it appears in your log aggregation system. Fifth, not handling the case where the banner fails silently. If your programmatic banner throws an exception, Spring Boot catches it and logs a warning, but the app still starts. This can mask configuration issues. Always log banner errors explicitly. Let's see how to use banner-mode=log.
spring.main.banner-mode=log and also add a Kubernetes liveness probe that checks for the banner in logs. If the banner doesn't appear within 30 seconds, the pod is restarted. It's a crude health check but works.banner-mode=log for containerized environments to ensure visibility in log aggregation systems.Putting It All Together: A Production-Ready Banner Strategy
Let's consolidate everything into a production-ready banner strategy for a microservice. The goal is to have a banner that is informative, safe, and environment-aware. First, create a base banner.txt with placeholders for version and profile. Second, create profile-specific overrides: banner-dev.txt with a fun ASCII cat, banner-staging.txt with a yellow warning, and banner-prod.txt with a red production warning. Third, implement a Banner interface class that reads build metadata from build-info.properties (generated by the Spring Boot Maven plugin) and displays it. Fourth, configure spring.main.banner-mode=log in all profiles except dev, where you use console for local development. Fifth, set spring.output.ansi.enabled=NEVER in production and staging. Sixth, add a test that verifies the banner contains the correct environment name for each profile. Finally, document the banner strategy in your team's runbook so operators know what to expect. This approach ensures that every time someone starts the service, they see critical context: environment, version, build number, and any warnings. It's a small effort that pays dividends during incident response. Let's see the complete configuration.
The Banner That Caused a 45-Minute Outage
${application.version} placeholder and added banner-prod.txt that includes environment name and build timestamp.- Never hardcode version or environment in banner.txt—always use placeholders or programmatic banners
- Treat the banner as a critical operational artifact, not a decoration
- Implement profile-specific banners to prevent confusion between dev/staging/prod
| File | Command / Code | Purpose |
|---|---|---|
| src | ____ _ _ ____ | Getting Started |
| CustomBanner.java | public class CustomBanner implements Banner { | What the Official Docs Won't Tell You |
| src | \u001B[31m ____ ____ ____ ____ ____ ____ | Profile-Specific Banners |
| BuildInfoBanner.java | public class BuildInfoBanner implements Banner { | Programmatic Banners with the Banner Interface |
| SafeColorBanner.java | public class SafeColorBanner implements Banner { | Advanced Techniques |
| BannerTest.java | @SpringBootTest(properties = "spring.main.banner-mode=console") | Testing Banners |
| application.properties | spring.main.banner-mode=log | Banner Anti-Patterns and Production Pitfalls |
| MyApp.java | @SpringBootApplication | Putting It All Together |
Key takeaways
Interview Questions on This Topic
How would you implement a banner that displays different messages based on the active Spring profile?
Frequently Asked Questions
20+ years shipping production Java in banking & fintech. Everything here is grounded in real deployments.
That's Spring Boot. Mark it forged?
6 min read · try the examples if you haven't