How to Use and Query TTL (Time to Live) in Apache Cassandra with Spring Data

What Is TTL in Cassandra?

TTL, or Time to Live, is a Cassandra feature that allows you to automatically expire rows or columns after a given time period. Instead of manually deleting old data, Cassandra automatically marks expired data as deleted (tombstoned) and removes it during compaction.

TTL values are set in seconds and can be applied to entire rows or individual columns.


Basic Example — Setting TTL in CQL

INSERT INTO user_sessions (user_id, session_id, last_access)
VALUES ('u123', 's456', toTimestamp(now()))
USING TTL 86400;

What happens:
The row will automatically expire after 24 hours (86,400 seconds).


Querying TTL for a Column

You can use the built-in TTL() function to check how long a specific column will remain in Cassandra before expiring.

SELECT TTL(last_access) FROM user_sessions
WHERE user_id = 'u123' AND session_id = 's456';

If the result is NULL, that means:

  • The column has no TTL set, or
  • The data has already expired and was compacted.

Querying TTL for Multiple Columns

You can check several TTLs at once:

SELECT TTL(column1), TTL(column2)
FROM table_name
WHERE id = '123';

Updating TTL for Existing Rows

You can refresh or extend the TTL of existing rows using an UPDATE query:

UPDATE user_sessions
USING TTL 172800
SET last_access = toTimestamp(now())
WHERE user_id = 'u123' AND session_id = 's456';

This resets the TTL to 48 hours (172,800 seconds).

To remove TTL entirely:

UPDATE user_sessions
USING TTL 0
SET last_access = toTimestamp(now())
WHERE user_id = 'u123' AND session_id = 's456';

⚠️ Setting TTL 0 marks the data for immediate expiration, but the actual deletion occurs asynchronously during compaction.


Using TTL in Spring Data Cassandra

Spring Data Cassandra makes it easy to work with TTL programmatically — both when inserting and updating data.


1. Setting TTL via @TimeToLive Annotation

You can annotate a field in your entity with @TimeToLive. The value (in seconds) will be automatically used as the TTL when the record is written.

import org.springframework.data.cassandra.core.mapping.*;
import java.time.Instant;

@Table("user_sessions")
public class UserSession {

    @PrimaryKey
    private String sessionId;

    private String userId;
    private Instant lastAccess;

    @TimeToLive
    private Integer ttl; // TTL in seconds

    // Getters and Setters
}

Then, in your service:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserSessionService {

    @Autowired
    private UserSessionRepository repository;

    public void createSession(String userId, String sessionId) {
        UserSession session = new UserSession();
        session.setUserId(userId);
        session.setSessionId(sessionId);
        session.setLastAccess(Instant.now());
        session.setTtl(86400); // 24 hours

        repository.save(session);
    }
}

2. Updating TTL for Existing Rows

Spring Data Cassandra doesn’t directly “update only the TTL” field, but you can re-save the object with a new TTL.

public void extendSessionTTL(String sessionId, int newTtl) {
    Optional<UserSession> opt = repository.findById(sessionId);
    if (opt.isPresent()) {
        UserSession session = opt.get();
        session.setTtl(newTtl);
        session.setLastAccess(Instant.now());
        repository.save(session);
    }
}

3. Updating TTL Using CassandraTemplate / CassandraOperations

If you want to set TTL dynamically or for a batch of records, you can use the lower-level API:

import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.data.cassandra.core.query.Query;
import org.springframework.data.cassandra.core.query.Update;
import org.springframework.data.cassandra.core.query.Criteria;
import org.springframework.stereotype.Service;

@Service
public class SessionTTLService {

    private final CassandraOperations cassandraOperations;

    public SessionTTLService(CassandraOperations cassandraOperations) {
        this.cassandraOperations = cassandraOperations;
    }

    public void expireSession(String sessionId) {
        Query query = Query.query(Criteria.where("session_id").is(sessionId));
        Update update = Update.empty().ttl(0); // expire immediately
        cassandraOperations.update(query, update, UserSession.class);
    }
}

This sets the TTL to 0, marking the record for immediate expiration.


4. Query TTL from Spring Boot

You can even retrieve TTL values directly from Cassandra using a custom CQL query.

@Query("SELECT TTL(last_access) FROM user_sessions WHERE session_id = ?0")
Integer getTTLBySessionId(String sessionId);

This returns the remaining TTL in seconds for the last_access column.


Practical Use Cases for TTL

  • Session Management – Expire sessions automatically after inactivity.
  • Caching Layers – Let temporary data expire naturally.
  • IoT Data Retention – Remove sensor readings after a retention window.
  • Logs and Audits – Automatically delete old entries to save storage.

Performance Considerations

  • Don’t use very short TTLs on large datasets — they produce many tombstones, increasing read latency.
  • Regular compaction is necessary to clear expired data efficiently.
  • Monitor performance metrics if you use TTL heavily across partitions.

Conclusion

Using TTL (Time to Live) in Cassandra is an elegant way to automate data expiration and simplify cleanup logic.
You can query TTL values using CQL’s built-in TTL() function, or manage them programmatically in Spring Boot via @TimeToLive or CassandraOperations.

With the right strategy, TTL helps maintain a lean, performant, and self-cleaning Cassandra cluster — without manual intervention.

This article is inspired by real-world challenges we tackle in our projects. If you're looking for expert solutions or need a team to bring your idea to life,

Let's talk!

    Please fill your details, and we will contact you back

      Please fill your details, and we will contact you back