Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

Multi-Tenancy no Node.js: isole clientes e dados

Atualizado em: 17 de outubro de 2026

Estação de trabalho usada no desenvolvimento de aplicações Node.js

Multi-Tenancy no Node.js permite que uma aplicação atenda várias organizações, clientes ou contas mantendo dados e configurações isolados. Cada tenant compartilha parte da infraestrutura, mas não deve acessar informações de outro.

O desafio principal não é adicionar um tenant_id. A identidade do tenant precisa atravessar autenticação, autorização, queries, cache, filas, logs, métricas e operações administrativas.

Modelos de isolamento

Existem três estratégias principais:

  • banco compartilhado e schema compartilhado: todas as tabelas possuem tenant_id;
  • schema por tenant: cada organização usa um schema separado;
  • banco por tenant: cada tenant possui banco ou cluster próprio.

Também é possível usar modelo híbrido, mantendo tenants menores compartilhados e tenants regulados em bancos dedicados.

Banco compartilhado

CREATE TABLE projetos (
  tenant_id uuid NOT NULL,
  id uuid NOT NULL,
  nome text NOT NULL,
  created_at timestamptz NOT NULL DEFAULT now(),
  PRIMARY KEY (tenant_id, id)
);

Incluir tenant_id na chave e nos índices reduz colisões e melhora consultas isoladas.

Resolver o tenant

O tenant pode vir de subdomínio, token, API key ou mapeamento do usuário. Não confie em um header enviado livremente sem validar a associação.

export function tenantMiddleware(req, res, next) {
  const tenantId = req.auth?.tenantId;
  if (!tenantId) return res.status(403).json({ error: 'Tenant obrigatório' });
  req.tenant = { id: tenantId };
  next();
}

Contexto por requisição

Use um objeto explícito ou AsyncLocalStorage para propagar tenant, usuário e trace. Contexto implícito ajuda em logs, mas repositories críticos ainda podem exigir tenantId como argumento.

Consulte AsyncLocalStorage no Node.js.

Repository isolado

export function criarProjetoRepository(db) {
  return {
    async obterPorId({ tenantId, projetoId }) {
      const result = await db.query(
        `SELECT * FROM projetos
         WHERE tenant_id = $1 AND id = $2`,
        [tenantId, projetoId]
      );
      return result.rows[0] ?? null;
    }
  };
}

Nunca busque apenas por id se o identificador não for global e o dado for tenant-scoped.

Row-Level Security

PostgreSQL pode aplicar Row-Level Security como defesa adicional.

ALTER TABLE projetos ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation ON projetos
USING (tenant_id = current_setting('app.tenant_id')::uuid)
WITH CHECK (tenant_id = current_setting('app.tenant_id')::uuid);

Dentro da transação:

await client.query(
  "SELECT set_config('app.tenant_id', $1, true)",
  [tenantId]
);

Use SET LOCAL ou configuração transacional para não vazar contexto entre conexões do pool.

Connection Pooling

Conexões são reutilizadas. Qualquer estado de sessão precisa ser limpo ou limitado à transação. Não associe permanentemente uma conexão compartilhada a um tenant.

Schema por tenant

O schema oferece separação maior, mas aumenta custo de migrations, conexões, catálogo e operação. Nunca construa search_path diretamente com entrada não validada.

Banco por tenant

Esse modelo melhora isolamento, backup e residência de dados, porém exige roteamento de conexões, muitos pools e automação de provisionamento.

Evite criar um pool ilimitado por tenant. Use cache com limite, expiração e fechamento de conexões.

Cache

A chave de cache deve incluir tenant.

const key = `tenant:${tenantId}:project:${projectId}`;

Uma chave sem tenant pode vazar dados mesmo quando o banco está protegido.

Filas e eventos

Inclua tenantId no envelope e valide antes de processar. Use a mesma informação para particionamento, autorização e observabilidade.

{
  "id": "evt-1",
  "type": "project.created.v1",
  "tenantId": "t-7",
  "data": { "projectId": "p-3" }
}

Autorização

Pertencer ao tenant não concede acesso a todos os recursos. Combine isolamento com RBAC ou ABAC.

Leia RBAC no Node.js e ABAC no Node.js.

Usuários em vários tenants

Modele associação separada entre usuário e tenant, com papéis próprios. A troca de tenant deve gerar novo contexto autorizado, não apenas alterar um valor no frontend.

Configuração por tenant

Planos, limites, integrações e feature flags podem variar. Valide configurações e mantenha defaults explícitos. Não leia configurações sensíveis de um tenant ao processar outro.

Rate limiting

Aplique limites por tenant, usuário e rota. Um tenant ruidoso não deve consumir toda a capacidade compartilhada.

Jobs e cron

Jobs globais precisam iterar tenants com paginação e limites. Registre checkpoint para retomar sem reprocessar todo o conjunto.

Migrations

No banco compartilhado, a migration é única. Em schema ou banco por tenant, execute versões de forma controlada e acompanhe tenants pendentes.

Consulte Database Migrations no Node.js.

Logs e métricas

Inclua tenant ID técnico em logs, traces e métricas, evitando nomes e dados pessoais. Cuidado com cardinalidade excessiva em métricas.

Backups e exclusão

Defina como restaurar ou excluir um tenant. Em banco compartilhado, restauração seletiva é mais complexa. Em banco dedicado, o ciclo de vida é mais isolado.

Administração

Ferramentas internas que atravessam tenants precisam de autorização reforçada, auditoria e motivo de acesso. Evite “modo superadmin” sem rastreabilidade.

Testes de isolamento

  • usuário de um tenant consulta ID de outro;
  • cache possui IDs iguais em tenants diferentes;
  • job recebe tenant incorreto;
  • conexão do pool mantém contexto anterior;
  • evento sem tenant;
  • exportação e backup;
  • admin acessa com auditoria;
  • RLS bloqueia query sem contexto.

Observabilidade

Monitore consumo, latência, erros e quotas por tenant. Tenants muito grandes podem precisar de particionamento ou infraestrutura dedicada.

Erros comuns

  • confiar em tenantId enviado pelo cliente;
  • query sem filtro;
  • cache sem namespace;
  • estado de sessão vazando no pool;
  • evento sem tenant;
  • logs com dados sensíveis;
  • pool ilimitado por tenant;
  • admin sem auditoria;
  • testar apenas caminho de sucesso.

Checklist

  • tenant vem de identidade validada;
  • queries e chaves incluem tenant;
  • RLS é considerada como defesa adicional;
  • cache e filas mantêm isolamento;
  • pool não vaza contexto;
  • autorização é aplicada dentro do tenant;
  • migrations e backups possuem estratégia;
  • testes tentam cruzar limites.

Conclusão

Multi-Tenancy no Node.js exige isolamento em todas as camadas, não apenas no banco. O tenant deve ser parte da identidade operacional da requisição e de qualquer mensagem assíncrona.

Comece pelo modelo mais simples que atende aos requisitos e adicione defesas como RLS, quotas e auditoria. Planeje desde cedo migrations, backups e tenants de grande porte.

Consulte a documentação de Row-Level Security do PostgreSQL e Connection Pooling no Node.js.

10 melhores cursos de programação em 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita