Which container types does @ServiceConnection support automatically, and how do you use it with a GenericContainer?
answer
- Specialized class = auto-detect
- GenericContainer = need name hint
- name = \"redis\" selects the factory
- withExposedPorts required for generic
- ConnectionDetailsFactory SPI matches type or name
basics
~20 sIt works out of the box with specialized Testcontainers classes like PostgreSQLContainer, MySQLContainer, MongoDBContainer, KafkaContainer, RabbitMQContainer, Neo4jContainer, etc. For a plain GenericContainer, Boot can't tell the service type, so you give it a hint: @ServiceConnection(name = "redis").
solid answer
~40 sBoot ships ConnectionDetailsFactory implementations for many services and auto-detects them from the specialized container class: PostgreSQL, MySQL, MariaDB, Oracle, MS SQL Server (JDBC and R2DBC), MongoDB, Neo4j, Cassandra, Elasticsearch, Kafka, RabbitMQ, Pulsar, Redis, ActiveMQ/Artemis, Zipkin, LDAP, and more. When you use a class like PostgreSQLContainer or KafkaContainer, the factory matches on that type, so a bare @ServiceConnection is enough. A GenericContainer carries no type information, so Boot can't infer the service — you must supply @ServiceConnection(name = "redis") (or the appropriate name), which tells Boot which ConnectionDetailsFactory to use. You still expose the right port with withExposedPorts(). If no factory matches the name or type, context startup fails, signalling the service isn't supported.
code
java · 14 lines@SpringBootTest
@Testcontainers
class CacheAndDbIT {
// Specialized class -> auto-detected, no hint needed
@Container @ServiceConnection
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16");
// GenericContainer -> service type unknown, must name it
@Container
@ServiceConnection(name = "redis")
static GenericContainer<?> redis =
new GenericContainer<>("redis:7").withExposedPorts(6379);
}go deeper
Should recall that databases/Kafka/Mongo work automatically and generic containers need a name.
Should list several supported types and correctly use @ServiceConnection(name=...) with GenericContainer plus withExposedPorts.
Should explain matching by container class vs by name via the ConnectionDetailsFactory SPI, and JDBC vs R2DBC factories.
Should know the extension point (custom ConnectionDetailsFactory) for services Boot doesn't ship.
## How Boot picks a factory Behind `@ServiceConnection` is the **`ConnectionDetailsFactory`** SPI (registered via Boot's auto-configuration metadata). Each factory declares which **container type** and/or **service name** it handles and knows how to read that container's host, mapped ports, and credentials into a typed `ConnectionDetails`. Matching happens two ways: 1. **By container class** — a `PostgreSQLContainer<?>` is recognized by the JDBC/R2DBC Postgres factory, a `KafkaContainer` by the Kafka factory, etc. Here a bare `@ServiceConnection` suffices. 2. **By name** — for containers whose class doesn't reveal the service (notably `GenericContainer`), you pass `@ServiceConnection(name = "...")` and Boot selects the factory registered under that connection name. ## Commonly supported services Spring Boot provides factories for (non-exhaustive): **PostgreSQL, MySQL, MariaDB, Oracle Free/XE, MS SQL Server** (both `JdbcConnectionDetails` and `R2dbcConnectionDetails`), **MongoDB, Neo4j, Cassandra, Couchbase, Elasticsearch, Redis, Kafka, RabbitMQ, Apache Pulsar, ActiveMQ/Artemis, Zipkin, OTLP, LDAP, InfluxDB**. Use the matching specialized Testcontainers class where one exists. ## GenericContainer usage Redis is the classic example — many teams run it via `GenericContainer` rather than a specialized class: ```java @Container @ServiceConnection(name = "redis") static GenericContainer<?> redis = new GenericContainer<>("redis:7").withExposedPorts(6379); ``` Here: - `withExposedPorts(6379)` is required so Testcontainers publishes the port and Boot can read the mapped one. - `name = "redis"` selects the Redis `ConnectionDetailsFactory`, producing a `RedisConnectionDetails`. Some factories can also match a `GenericContainer` by its **image name** (e.g. an image called `redis`), but relying on the explicit `name` attribute is the clearest, most portable approach. ## Edge cases and gotchas - **Wrong or missing name on a GenericContainer**: no factory matches, so no `ConnectionDetails` is created and beans fall back to defaults/properties (often failing to connect). If a name is given but unknown, startup fails clearly. - **Forgot withExposedPorts**: Boot can't find the port; connection details are incomplete. - **R2DBC vs JDBC**: the same database has separate factories; the right one is chosen based on what's on the classpath / requested — a Postgres container can yield either `JdbcConnectionDetails` or `R2dbcConnectionDetails`. - **Unsupported bespoke service**: you either write a custom `ConnectionDetailsFactory` or fall back to `@DynamicPropertySource`.
- Why does @ServiceConnection on a GenericContainer need a name but not on a PostgreSQLContainer?PostgreSQLContainer's class identifies the service so the factory matches by type. GenericContainer is untyped, so Boot needs the name hint to pick the right ConnectionDetailsFactory.
- What happens if you omit withExposedPorts on the generic Redis container?Testcontainers won't publish the port and Boot can't determine the mapped port, so the derived RedisConnectionDetails is incomplete and the connection fails.
saying these in an interview costs you the question
- Saying any Docker image works automatically (only services with a ConnectionDetailsFactory are supported).
- Putting name = "redis" on a specialized container where it's unnecessary or wrong.
- Forgetting that GenericContainer needs both a name hint and withExposedPorts.