Limitador de requisições no NestJS com Throttler + Redis: passo a passo para iniciantes
Por John Pires · 10 de março de 2026

Contexto: quando você vai usar isso
Proteção contra abuso e picos de tráfego é uma necessidade básica em qualquer API pública. Para quem está começando, fazer rate limiting pode parecer complicado, mas a ideia central é simples: limitar quantas requisições um cliente pode fazer em um intervalo de tempo.
No ecossistema NestJS existe o pacote oficial @nestjs/throttler que resolve essa necessidade com integrações fáceis. Porém, o armazenamento padrão é em memória, o que é problemático em ambientes com múltiplas instâncias. É aí que o Redis entra: ele fornece um armazenamento centralizado, rápido e compartilhado entre instâncias.
Este artigo guia você, passo a passo, na configuração do Throttler com Redis — desde o básico em memória até a configuração com Redis e dicas práticas de produção. O foco é ser didático: analogias simples, comandos reais e exemplos funcionais para experimentar localmente.
Você deve aplicar isso quando: expor endpoints públicos, quiser limitar acesso a rotas sensíveis, proteger rotas autenticadas de abuso ou controlar bots e scraping.
O que o Throttler resolve
O Throttler faz o trabalho de contar requisições por chave (IP ou outro identificador) e retornar HTTP 429 quando o limite é ultrapassado. A biblioteca trata TTL, contagem e integração com Guards do NestJS.
Por que usar Redis
Redis é um banco de dados em memória rápido e compartilhado. Em arquiteturas com múltiplas instâncias da API (containers, máquinas), um armazenamento centralizado evita que cada instância tenha contadores diferentes, o que quebraria o controle de limite.
Explicação visual com diagramas mentais
Imagine o rate limiter como um porteiro em frente a um prédio:
- Cada visitante (requisição) desfila para o porteiro.
- O porteiro consulta um caderno central (Redis) que conta quantas vezes o visitante já entrou no período.
- Se a contagem exceder o permitido, o porteiro bloqueia a entrada (HTTP 429).
Quando só existe um porteiro (uma instância), um caderno local funciona. Mas com vários porteiros (várias instâncias), o caderno precisa ser o mesmo para todos — é o papel do Redis.
Fluxo mental passo a passo
- Requisição chega ao NestJS.
- Guard de Throttler calcula a chave (por IP ou anotação do usuário).
- Guard pede ao armazenamento (memória ou Redis) a contagem atual.
- Se contagem < limite, incrementa e permite; caso contrário, retorna 429.
Componentes envolvidos
- ThrottlerModule: configura ttl e limite padrão.
- ThrottlerGuard: guard global ou por controlador/rota.
- ThrottlerStorage (Redis): implementação do armazenamento.
- Decorators: @Throttle e @SkipThrottle para rotas específicas.
Dica: em desenvolvimento, testar primeiro em memória para validar lógica; em staging/prod, passar para Redis para consistência entre instâncias.
Primeiro exemplo simples (em memória)
Vamos montar uma API mínima com NestJS e aplicar Throttler em memória. Serve para validar comportamento antes de integrar Redis.
Instalação rápida
Execute estes comandos no terminal do seu projeto NestJS:
npm install @nestjs/throttler
Contexto: o comando instala o módulo de rate limiting do NestJS. A partir daqui vamos configurar o módulo na aplicação.
Configuração básica no AppModule
Crie ou abra src/app.module.ts e adicione o ThrottlerModule. Abaixo tem um exemplo funcional que aplica limite global de 10 requisições por 60 segundos e registra o ThrottlerGuard global via provider APP_GUARD.
import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler';
import { AppController } from './app.controller';
@Module({
imports: [
ThrottlerModule.forRoot({
ttl: 60, // tempo em segundos
limit: 10, // número de requisições permitidas no TTL
}),
],
controllers: [AppController],
providers: [
{
provide: APP_GUARD,
useClass: ThrottlerGuard,
},
],
})
export class AppModule {}
O que faz: registra o módulo para usar guard global. O que acontece: agora todas rotas da aplicação respeitam 10 requisições por 60s por chave padrão (IP).
Controller de exemplo
Crie um controller simples com uma rota que respeita o throttle padrão e outra que define limite personalizado com o decorator @Throttle.
import { Controller, Get } from '@nestjs/common';
import { Throttle, SkipThrottle } from '@nestjs/throttler';
@Controller('demo')
export class AppController {
@Get('default')
default() {
return { ok: true, msg: 'rota padrão com limite global' };
}
@Get('tight')
@Throttle(2, 30) // 2 requisições a cada 30 segundos
tight() {
return { ok: true, msg: 'rota com limite mais restrito' };
}
@Get('open')
@SkipThrottle()
open() {
return { ok: true, msg: 'rota sem limite (use com cuidado)' };
}
}
O que faz: demonstra uso de @Throttle e @SkipThrottle. O que acontece: você pode testar com curl ou Postman e observar 429 quando limites são atingidos.
Segundo exemplo mais realista (Throttler + Redis)
Agora que você validou o comportamento com memória, vamos integrar Redis para uso em produção ou em setups com múltiplas instâncias. Usaremos o pacote de armazenamento Redis compatível com Throttler e o cliente ioredis.
Instalação e serviços necessários
Instale dependências e garanta que o Redis esteja disponível localmente ou em um endpoint gerenciado:
npm install @nestjs/throttler throttler-storage-redis ioredis
# certifique-se de ter o redis rodando em localhost:6379
Contexto: o pacote throttler-storage-redis fornece uma implementação que o Throttler consegue usar como armazenamento. ioredis é cliente robusto para Node.js.
Configuração com ThrottlerModule.forRootAsync
Abaixo um AppModule que usa ThrottlerModule.forRootAsync para criar a instância de armazenamento Redis com variáveis de ambiente. Esse padrão facilita trocar configurações por ambiente.
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { ThrottlerModule } from '@nestjs/throttler';
import { ThrottlerStorageRedisService } from 'throttler-storage-redis';
import { APP_GUARD } from '@nestjs/core';
import { ThrottlerGuard } from '@nestjs/throttler';
import { AppController } from './app.controller';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (config: ConfigService) => ({
ttl: 60,
limit: 20,
storage: new ThrottlerStorageRedisService({
host: config.get('REDIS_HOST', '127.0.0.1'),
port: +config.get('REDIS_PORT', 6379),
}),
}),
}),
],
controllers: [AppController],
providers: [
{
provide: APP_GUARD,
useClass: ThrottlerGuard,
},
],
})
export class AppModule {}
O que faz: registra Throttler com armazenamento Redis. O que acontece: as contagens são gravadas no Redis, permitindo consistência em instâncias múltiplas.
Testando em cluster ou com Docker
Em Docker Compose, exponha múltiplos containers da sua API apontando para o mesmo serviço Redis. Você verá que as requisições somam no mesmo contador central.
version: '3.7'
services:
redis:
image: redis:6
ports:
- '6379:6379'
api:
build: .
environment:
REDIS_HOST: redis
depends_on:
- redis
ports:
- '3000:3000'
deploy:
replicas: 2
Contexto: este docker-compose simples ilustra várias réplicas da mesma API conectando num único Redis. O que acontece: o Throttler passa a contar globalmente entre réplicas.
Erros comuns de iniciante e como evitar
Mesmo com exemplos prontos, iniciantes cometem erros frequentes que quebram o rate limiting ou causam comportamento inesperado. Listei os principais com soluções práticas.
1) Esquecer de registrar o APP_GUARD
Erro: instalar ThrottlerModule, mas não registrar o ThrottlerGuard global. Resultado: decorators como @Throttle não são aplicados automaticamente e suas rotas não serão protegidas.
Solução: garantir provider APP_GUARD apontando para ThrottlerGuard no array providers do módulo raiz (veja exemplos acima).
2) Usar armazenamento em memória em produção
Erro: manter configuração padrão em memória em ambiente com múltiplas instâncias. Resultado: cada instância conta separadamente e o rate limit é inefetivo.
Solução: usar Redis (ou outro storage compartilhado). Em Kubernetes ou containers, sempre prefira Redis para rate limiting.
3) Não lidar com proxy / X-Forwarded-For
Erro: o Throttler por padrão usa o IP remoto direto. Em infra com proxy reverso (NGINX, ALB) o IP pode ser do proxy, causando todos requests parecerem vir do mesmo IP.
Solução: configurar NestJS para confiar no proxy e usar cabeçalho X-Forwarded-For para extrair IP real. No NestJS, configure app.set('trust proxy', 1) no bootstrap, e verifique como o Throttler calcula a chave. Alternativamente, crie um ThrottlerGuard custom que usa o header para formar a chave.
4) TTL mal interpretado ou clocks diferentes
Erro: inconsistência de tempo entre instâncias (clock skew) pode afetar expiração de chaves no Redis.
Solução: sincronize NTP nos servidores e prefira usar TTL em segundos com Redis. Teste comportamento com clocks controlados e monitore Expire dos keys no Redis.
Dicas práticas e troubleshooting
- Use redis-cli para inspecionar chaves criadas pelo Throttler e verificar valores e TTL.
- Logs de 429 devem incluir informação suficiente para reproduzir: IP, rota e contador atual.
- Em ambientes serverless, evite armazenamento em memória. Prefira Redis gerenciado.
Dica: antes de mover para produção, rode testes de carga simples (wrk, vegeta) para validar limites e observar comportamento real do Throttler+Redis.
Conclusão prática
Você aprendeu quando e por que usar Throttler no NestJS, e como integrar com Redis para produção. O caminho recomendado para iniciantes é: implementar primeiro em memória para validar a lógica, depois migrar para Redis para garantir consistência entre instâncias.
Resumo das ações práticas:
- Instale @nestjs/throttler e valide limites locais em memória.
- Adicione APP_GUARD com ThrottlerGuard para proteção global.
- Se escalar para múltiplas instâncias, instale throttler-storage-redis + ioredis e configure ThrottlerModule.forRootAsync com ThrottlerStorageRedisService.
- Trate proxy/IP real e teste com ferramentas de carga.
Para seguir em frente, teste os exemplos apresentados, observe as chaves no Redis e experimente ajustar ttl/limit para sua aplicação. Rate limiting bem aplicado reduz abuso, mantém disponibilidade e protege custos.
Se quiser, posso fornecer um repositório de exemplo completo (Docker + NestJS) pronto para clonar e rodar localmente, com scripts de teste de carga e dashboards para monitorar contadores no Redis.
Boa prática: mantenha logs claros de 429, monitore Redis (latência e uso de memória) e ajuste limites com base em métricas reais de uso.
Assuntos: NestJS, throttler, NoSQL, guards, rate-limiting
Leia também
NestJS: criar e testar microservice TCP e gateway HTTP passo a passo
Passo a passo prático para criar e testar um microservice TCP em NestJS e um gateway HTTP. Mostro o jeito errado, o jeito certo, exemplos funcionais e como…
Propagando contexto de requisição e trace IDs entre microservices com NestJS
Guia prático para propagar trace IDs em NestJS: middleware, AsyncLocalStorage, interceptors e wrappers de ClientProxy. Padrões, armadilhas e exemplos reais…
Rate limiting por usuário no NestJS com Guard + Redis (sliding window)
Aprenda a implementar rate limiting por usuário no NestJS usando Guard + Redis com sliding window. Guia passo a passo, exemplos práticos (Lua + ioredis)…
Autorização por permissões no NestJS usando decorators e guards
Aprenda a controlar autorização por permissões no NestJS usando decorators e guards. Tutorial prático, passo a passo, com exemplos funcionais, integração JWT…
Testando Guards e Interceptors no NestJS com Jest e SuperTest — do jeito errado ao certo
Guards controlam acesso e Interceptors transformam respostas. Aprenda a testar ambos no NestJS: mostro o jeito errado, corrijo e explico testes unitários e…
Autenticação JWT segura no NestJS com refresh tokens rotativos e Redis
Implementação prática de autenticação JWT no NestJS com refresh tokens rotativos, armazenamento de jti em Redis e detecção de replay. Guia com exemplos de…