Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogCoursesPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Courses
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
Tech NewsJune 25, 20264 min read

Postgres Rate Limiting and Redis Patterns for Multi-Tenant APIs

Master Postgres rate limiting and Redis API throttling to secure your multi-tenant architecture. Learn a hybrid approach for scalable, reliable performance.

PostgresRedisSaaSAPI SecurityMulti-tenancyBackend ArchitectureNewsTrendsIndustry

When I first started building multi-tenant systems, I thought a simple middleware check would be enough to protect our database. I was wrong. During an on-call rotation last year, a single noisy tenant spiked their request volume by roughly 4x, effectively bypassing our application-level guards and saturating our primary write node. We needed a more robust strategy that combined the speed of memory-backed stores with the ground-truth authority of our relational database.

If you’re managing a SaaS, you know that keeping one tenant from starving others is the primary challenge. To solve this, I’ve settled on a hybrid approach: using Redis for immediate, low-latency traffic shaping and Postgres for persistent, policy-enforced governance.

Why You Need Hybrid Postgres Rate Limiting

The main issue with relying solely on Redis for API throttling is that state can be lost during evictions or cluster rebalancing. While Redis is incredibly fast—typically handling requests in under 1ms—it isn't the source of truth for your tenant's subscription limits.

We first tried implementing a pure Redis-based token bucket, as discussed in API Rate Limiting with Token Bucket Algorithms for Multi-Tenant SaaS. It worked well for standard traffic, but it failed when we needed to adjust limits dynamically based on a user's billing tier changes in the database. When the Redis key expired or was flushed, the system defaulted to "unlimited" until the next sync, which was a security gap we couldn't ignore.

The Redis-Postgres Integration Pattern

Instead of choosing one, we use both. Redis acts as the "fast path" for checking current consumption, while Postgres stores the "authoritative limit" for the tenant.

Here is the flow:

  1. Request Hit: The API gateway checks Redis for the tenant's current bucket.
  2. Fast Path: If the count is below the threshold, the request proceeds.
  3. Sync Path: Every 30 seconds (or on a specific event), we persist the consumption count to Postgres to ensure we have a record of usage.

This pattern is far more reliable than relying on Laravel Redis Lua Scripting for Deterministic Rate Limiting in isolation, especially if your architecture involves multiple services that need to share a global state.

Implementing the Database Layer

When Redis isn't enough, you should look into Database performance: Throttling Queries with Row-Level Constraints to enforce hard limits at the persistence layer. By using Postgres triggers or check constraints, you can prevent a tenant from exceeding their quota even if your application code has a bug.

SQL
-- A simple check to prevent exceeding plan limits
ALTER TABLE tenant_usage 
ADD CONSTRAINT check_daily_limit 
CHECK (daily_requests <= max_allowed_requests);

While this looks simple, it adds a layer of protection that saves you when a rogue script starts hammering your endpoints. If you’re already using Postgres RLS for Multi-Tenant SaaS: A Practical Implementation Guide, you can extend your RLS policies to check these usage columns in real-time, effectively creating a "deny-all" state for over-limit tenants.

Trade-offs and Lessons Learned

The biggest trade-off here is complexity. You now have two systems to monitor. If your Redis instance goes down, your application needs a fail-safe. In our case, we set the application to "fail open" to the database if Redis is unreachable for more than about 280ms. It’s not perfect, but it keeps the service running while we investigate the cache issues.

I’ve also learned that you shouldn't try to sync every single request back to Postgres. That’s a recipe for database contention. We use an asynchronous worker to batch updates, which keeps our write IOPS manageable.

Frequently Asked Questions

Does this increase latency? The Redis check adds less than 1ms to the request cycle. The database persistence happens asynchronously, so it doesn't impact the end-user response time.

What happens if the database and Redis get out of sync? We run a daily reconciliation job that calculates the actual usage from our logs and updates the Redis buckets. It’s a "self-healing" pattern that we've found essential for production stability.

Is this overkill for small apps? Probably. If you're just starting, keep it simple. Only move to this hybrid model once you have enough tenants that individual noisy neighbors start impacting your system's P99 latency.

I’m still experimenting with using materialized views for these lookups to further reduce the load on our primary tables. It feels like the right direction, but I'm cautious about the overhead of refreshing views under high write volume. Building these systems is always a balancing act between strict enforcement and keeping the user experience snappy.

Back to Blog

Similar Posts

Tech NewsJune 23, 20263 min read

Postgres RLS for Multi-Tenant SaaS: A Practical Implementation Guide

Master Postgres RLS to enforce data isolation in your multi-tenant SaaS architecture. Learn how to secure shared databases without sacrificing performance.

Read more
Tech NewsJune 24, 20263 min read

Redis Vector Search: Tuning RediSearch for Low-Latency Retrieval

Redis vector search performance depends on your index configuration. Learn to tune HNSW parameters and optimize RediSearch to hit sub-10ms retrieval latency.

Read more
Close-up of a hand adjusting a chess clock during a timed chess game indoors.
Tech NewsJune 20, 20264 min read

Postgres logical decoding for real-time CDC: A Practical Guide

Master Postgres logical decoding for real-time CDC. Learn how to stream database changes effectively to build robust, event-driven architectures today.

Read more