---
title: "Supabase exposed schemas: o que a lista expõe"
description: "O que significa Exposed schemas no Supabase, como o meu verificador classifica schemas extra e uma consulta SQL que encontra tabelas sem RLS neles."
url: "https://madsalt.tech/pt/notes/supabase-exposed-schemas/"
author: "Denys Zaichenko"
language: "pt"
published: 2026-10-22
---

# Supabase exposed schemas: o que a lista expõe

Em resumo

A lista Exposed schemas do Supabase decide que schemas a Data API serve a quem tiver a sua chave pública. Por omissão são `public` e `graphql_public`. Cada tabela, vista e função de um schema da lista precisa dos seus próprios grants e de RLS, por isso cada schema extra é mais superfície a defender. Mantenha a lista curta e verifique-a primeiro.

Criei um [verificador de segurança do Supabase](https://madsalt.tech/pt/tools/supabase-security-check/) gratuito, e a lista Exposed schemas é uma das primeiras coisas que ele lê. Quando alguém pergunta se um projeto Supabase é seguro, é por esta definição que começo.

## O que significa schema exposto no Supabase?

O Supabase serve a sua base de dados por REST com o PostgREST. O PostgREST só responde pelos schemas da sua lista `db_schema`, que se edita no Dashboard em Project Settings → Data API → Exposed schemas. Na configuração do projeto que vi, o valor era `public,graphql_public`, e o [guia de schemas personalizados](https://supabase.com/docs/guides/api/using-custom-schemas) do Supabase diz que o `public` é exposto por omissão. Um pedido a um schema fora da lista é recusado, e o [PostgREST](https://docs.postgrest.org/en/stable/references/api/schemas.html) nunca permite `pg_catalog` nem `information_schema` nela.

## Porque é que a lista importa para a segurança do Supabase?

Tudo o que está num schema exposto é alcançável com a chave pública: tabelas, vistas e funções. O [guia de RLS](https://supabase.com/docs/guides/database/postgres/row-level-security) do Supabase é direto: uma tabela num schema exposto sem RLS pode ser lida e escrita por qualquer função com um grant sobre ela. Um schema que não está na lista não pode ser alcançado de todo pela API.

Por isso, um schema extra não é uma alteração neutra. Junte `storage` ou `vault` à lista e coloca tabelas internas ao alcance da Data API. Junte o seu próprio schema e cada tabela dele precisa do mesmo cuidado que o `public`.

![O que abre um schema exposto a mais. Um pedido anon, antes e depois de reduzir a lista. Antes: um schema extra exposto: pedido anon → Data API → schema extra → tabela sem RLS legível; Depois: só public e graphql_public: pedido anon → Data API → só schemas por omissão → RLS em cada tabela.](https://madsalt.tech/charts/pt/supabase-exposed-schemas.svg)

*Das regras do verificador de segurança do Supabase e da documentação da Data API do Supabase, 22 de outubro de 2026.*

## Como é que o verificador classifica a lista?

A verificação chama-se `extra_exposed_schemas`. Tudo o que não for `public` nem `graphql_public` conta como extra, e depois:

- Um schema interno do Supabase na lista (`auth`, `storage`, `realtime`, `vault`, `extensions` e semelhantes) é uma **falha, gravidade alta**.
- Só schemas personalizados, por exemplo `api`, dão um **aviso, gravidade média**.
- Sem extras, passa.

A mesma lista alimenta outras verificações. Tabelas com RLS desligado, grants de escrita ao anon, políticas sempre verdadeiras, vistas sem `security_invoker` e funções `SECURITY DEFINER` que o anon pode chamar só são reportadas para schemas expostos, porque é aí que a chave pública lá chega.

## Como usar um schema personalizado em segurança?

Um schema personalizado é um padrão legítimo: o guia [Securing your API](https://supabase.com/docs/guides/api/securing-your-api) do Supabase descreve um schema dedicado, como `api`, como forma de tornar a superfície exposta mais fácil de identificar e auditar, com as tabelas internas em schemas que não são expostos. Dois passos fazem-no funcionar, e o [guia de schemas personalizados](https://supabase.com/docs/guides/api/using-custom-schemas) dá os dois: juntar o schema a Exposed schemas e depois conceder `usage` sobre ele a `anon`, `authenticated` e `service_role`, mais privilégios sobre os seus objetos.

O exemplo do guia concede `ALL` em todas as tabelas. Eu não copiaria essa linha tal como está. O guia Securing your API manda dar a cada função o mínimo de que precisa e ativar o RLS em todas as tabelas que expõe. Os grants decidem se uma função pode tocar numa tabela, as políticas decidem que linhas.

Uma alteração à parte: o Supabase [deixa de conceder automaticamente à Data API as novas tabelas de `public`](https://supabase.com/changelog/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically). Passou a ser o padrão nos projetos novos desde 30 de maio de 2026 e será aplicado aos projetos existentes em 30 de outubro de 2026, e as tabelas existentes mantêm os grants. Essa é a camada dos grants. Não muda os schemas que estão na lista.

## Como verificar o seu projeto?

Abra Project Settings → Data API e leia Exposed schemas. Se for mais do que `public` e `graphql_public`, pergunte para que serve cada schema extra.

Depois liste as tabelas desses schemas que têm o RLS desligado, e se o `anon` já as pode ler:

```sql
select n.nspname as schema,
       c.relname as "table",
       has_table_privilege('anon', c.oid, 'select') as anon_can_select
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
where n.nspname in ('public', 'api')  -- your Exposed schemas
  and c.relkind in ('r', 'p')
  and not c.relrowsecurity
order by 1, 2;
```

Corri-a num Postgres 17 descartável, com um schema `api` que tinha uma tabela com RLS e outra sem, mais uma tabela `public` sem RLS. Devolveu só as duas sem:

```text
 schema | table  | anon_can_select
--------+--------+-----------------
 api    | orders | t
 public | logs   | t
```

Cada linha com `anon_can_select` verdadeiro é uma tabela que qualquer pessoa com a sua chave pública consegue ler, até ativar o RLS ou revogar o grant. A consulta cobre apenas tabelas. As vistas e as funções pedem a sua própria análise, que é o que a minha [lista de segurança para apps Lovable](https://madsalt.tech/pt/blog/lovable-app-security-checklist/) percorre, e [como testo o Supabase RLS](https://madsalt.tech/pt/blog/how-to-test-supabase-rls/) mostra como provar que as políticas funcionam.
