How to connect a Spring Boot application to MongoDB?

Connecting Spring Boot to MongoDB is a very common task for modern Java apps.



This guide walks you through everything you need: project setup (Maven/Gradle), configuration, domain mapping, repositories (Spring Data MongoDB), advanced options (MongoTemplate, transactions), local development with Docker, testing, troubleshooting, and security tips. I’ll include runnable code snippets so you can copy-paste and get started quickly.

What you’ll learn

• Required dependencies (Maven & Gradle)

• application.properties / application.yml examples (local, auth, replica set)

• Domain classes and repositories using Spring Data MongoRepository

• Using MongoTemplate and custom queries

• Enabling and using transactions

• Running MongoDB locally with Docker (including a single-node replica set)

• Integration testing with embedded MongoDB (Flapdoodle)

• Common problems and fixes, plus security best practices

Prerequisites

• Java 11+ (or Java 8 if you must; modern Spring Boot prefers 11+)

• Maven or Gradle

• Spring Boot (2.5+ or 3.x — examples assume Spring Boot starters)

• MongoDB server (local, Docker, or managed cloud like Atlas)

1 — Add dependencies

Maven (pom.xml)

<dependencies>

<! — Spring Boot starter for web (optional, if building REST API) →

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

<! — Spring Data MongoDB →

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-mongodb</artifactId>

</dependency>

<! — Optional: embed MongoDB for tests →

<dependency>

<groupId>de.flapdoodle.embed</groupId>

<artifactId>de.flapdoodle.embed.mongo</artifactId>

<scope>test</scope>

</dependency>

</dependencies>

Gradle (build.gradle.kts)

dependencies {

implementation(“org.springframework.boot:spring-boot-starter-web”)

implementation(“org.springframework.boot:spring-boot-starter-data-mongodb”)

testImplementation(“de.flapdoodle.embed:de.flapdoodle.embed.mongo”)

}

2 — Configure connection (application.properties / application.yml)

You can put your connection string in application.properties or application.yml. It’s recommended to use environment variables for credentials in production.

Simple local (no auth) — application.properties

spring.data.mongodb.database=mydb

spring.data.mongodb.uri=mongodb://localhost:27017/mydb

Using credentials and options

spring.data.mongodb.uri=mongodb://user:password@localhost:27017/mydb?authSource=admin&retryWrites=true&w=majority

YAML version (application.yml)

spring:

data:

mongodb:

uri: mongodb://user:password@localhost:27017/mydb?authSource=admin&retryWrites=true&w=majority

Replica set (required for transactions)

spring.data.mongodb.uri=mongodb://user:password@mongo1:27017,mongo2:27017,mongo3:27017/mydb?replicaSet=rs0&retryWrites=true&w=majority

3 — Domain model & repository (Spring Data)

Example domain class

package com.example.demo.model;

import org.springframework.data.annotation.Id;

import org.springframework.data.mongodb.core.mapping.Document;

import java.time.LocalDateTime;

@Document(collection = “products”)

public class Product {

@Id

private String id; // stores MongoDB ObjectId as hex string

private String name;

private String description;

private double price;

private LocalDateTime createdAt;

// getters, setters, constructors…

}

Notes:

Use @Document(collection = “name”) to map the collection.

@Id can be String or org.bson.types.ObjectId. Using String is convenient because Spring converts for you.

Repository interface

package com.example.demo.repo;

import com.example.demo.model.Product;

import org.springframework.data.mongodb.repository.MongoRepository;

import java.util.List;

public interface ProductRepository extends MongoRepository<Product, String> {

List<Product> findByNameContainingIgnoreCase(String nameFragment);

}

Spring Data generates implementation automatically. Use typical CRUD methods: save, findById, findAll, deleteById.

4 — Service and Controller (example REST CRUD)

Service (simple)

@Service

public class ProductService {

private final ProductRepository repo;

public ProductService(ProductRepository repo) { this.repo = repo; }

public Product create(Product p) {

p.setCreatedAt(LocalDateTime.now());

return repo.save(p);

}

public Optional<Product> getById(String id) { return repo.findById(id); }

public List<Product> search(String q) { return repo.findByNameContainingIgnoreCase(q); }

public void delete(String id) { repo.deleteById(id); }

}

Controller

@RestController

@RequestMapping(“/api/products”)

public class ProductController {

private final ProductService svc;

public ProductController(ProductService svc) { this.svc = svc; }

@PostMapping

public ResponseEntity<Product> create(@RequestBody Product p) {

return ResponseEntity.status(HttpStatus.CREATED).body(svc.create(p));

}

@GetMapping(“/{id}”)

public ResponseEntity<Product> get(@PathVariable String id) {

return svc.getById(id).map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build());

}

@GetMapping(“/search”)

public List<Product> search(@RequestParam String q) { return svc.search(q); }

@DeleteMapping(“/{id}”)

public ResponseEntity<Void> delete(@PathVariable String id) {

svc.delete(id);

return ResponseEntity.noContent().build();

}

}

5 — Using MongoTemplate for custom queries

MongoRepository covers many use-cases; MongoTemplate is useful for complex queries or aggregations.

@Service

public class CustomProductService {

private final MongoTemplate mongoTemplate;

public CustomProductService(MongoTemplate mongoTemplate) { this.mongoTemplate = mongoTemplate; }

public List<Product> findExpensiveProducts(double minPrice) {

Query q = new Query(Criteria.where(“price”).gte(minPrice));

q.with(Sort.by(Sort.Direction.DESC, “price”));

return mongoTemplate.find(q, Product.class);

}

}

MongoTemplate also supports aggregation pipelines with Aggregation classes.

6 — Transactions with MongoDB

MongoDB supports multi-document transactions starting with 4.0, but they require a replica set (even single-node replica set). Spring provides MongoTransactionManager.

Spring config for transactions

@Configuration

@EnableTransactionManagement

public class MongoConfig {

@Bean

MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {

return new MongoTransactionManager(dbFactory);

}

}

Using transactions

@Transactional

public void performMultipleOps() {

// multiple repository saves or template operations will be in same transaction

repo.save(entity1);

repo.save(entity2);

}

Remember: to use transactions locally, your Mongo instance must be a replica set. See Docker section below.

7 — Run MongoDB locally with Docker (single-node replica set for transactions)

A minimal docker-compose for a single-node replica set:

version: “3.8”

services:

mongo:

image: mongo:6 # or your preferred version

container_name: mongo

ports:

- “27017:27017”

command: [“mongod”, “ — replSet”, “rs0”, “ — bind_ip_all”]

volumes:

- ./mongo-data:/data/db

Start:

docker-compose up -d

Initialize replica set:

# either use mongosh inside container

docker exec -it mongo mongosh — eval “rs.initiate()”

If you need auth, create an admin user:

docker exec -it mongo mongosh

> use admin

> db.createUser({user: “admin”, pwd: “securepass”, roles:[“root”]})

Then use the URI with credentials:

mongodb://admin:securepass@localhost:27017/?authSource=admin&replicaSet=rs0

8 — Integration testing: Flapdoodle embedded Mongo

Add Flapdoodle dependency (already shown earlier). In tests, Spring Boot auto-config will connect to embedded Mongo when available.

Example JUnit 5 test:

@SpringBootTest

@AutoConfigureDataMongo

public class ProductRepositoryTests {

@Autowired

private ProductRepository repo;

@Test

void testSaveAndFind() {

Product p = new Product(null, “Test”, “desc”, 9.99, LocalDateTime.now());

repo.save(p);

assertFalse(repo.findById(p.getId()).isEmpty());

}

}

This is great for CI because it avoids requiring external MongoDB.

9 — Practical tips, gotchas & troubleshooting

Connection refused: check Mongo server is running and correct host/port. If running in Docker, confirm ports and network.

Authentication failed: ensure correct authSource (often admin) and that the user exists in that DB.

Replica set required for transactions: if transactions fail, verify rs.status() and that replicaSet option is set in URI.

SSL/TLS errors: add tls=true and proper certificates, or disable certificate validation only for dev (not recommended for prod).

ObjectId mapping: if using String for @Id, Spring maps it to/from ObjectId automatically. If you use ObjectId type, import org.bson.types.ObjectId.

Indexes: create indexes for frequently queried fields. You can annotate your model with @Indexed:

@Indexed(direction = IndexDirection.DESCENDING)

private LocalDateTime createdAt;

Performance: avoid unbounded queries (large pages). Use pagination with Pageable.

Document design: MongoDB favors denormalized documents for read performance. Embed sub-documents when they are accessed together.

10 — Security & production best practices

Do not hardcode credentials in application.properties. Use environment variables or secret managers.

spring.data.mongodb.uri=${MONGODB_URI}

Least privilege: create separate DB users with least privilege needed.

TLS: enable TLS for in-transit encryption.

IP whitelisting: only allow known IPs in cloud-managed MongoDB (Atlas).

Monitoring: enable monitoring/metrics (MongoDB Ops Manager, Atlas, or Prometheus exporters).

Backups: schedule periodic backups and test restores regularly.

11 — Quick checklist before you deploy

Connection string stored securely (env var / vault)

Proper user roles & authSource configured

Replica set configured if you require transactions

Indexes created for critical queries

Secrets rotated regularly

Monitoring and backups enabled

Example: full application.yml for production (env vars)

spring:

data:

mongodb:

uri: ${MONGODB_URI}

Where MONGODB_URI might be:

mongodb://appuser:secret@mongo1:27017,mongo2:27017/mydb?authSource=admin&replicaSet=rs0&retryWrites=true&w=majority

Spring Data MongoDB makes it very quick to get started: define your domain, repository, and start CRUD operations.

For complex operations, MongoTemplate and aggregation pipelines cover the gaps.

Always test locally (Docker or embedded Mongo) and validate replica set & auth configuration if you need transactions.

Post a Comment

0 Comments