---
title: "Supabase exposed schemas: hva listen åpner for"
description: "Supabase exposed schemas forklart: hva innstillingen betyr, hvordan sjekken min vurderer ekstra skjemaer, og ett SQL-spørsmål som finner tabeller uten RLS."
url: "https://madsalt.tech/no/notes/supabase-exposed-schemas/"
author: "Denys Zaichenko"
language: "no"
published: 2026-10-22
---

# Supabase exposed schemas: hva listen åpner for

TL;DR

Listen Exposed schemas i Supabase bestemmer hvilke skjemaer Data API-et serverer til alle som har den offentlige nøkkelen din. Standarden er `public` og `graphql_public`. Hver tabell, view og funksjon i et skjema på listen må ha sine egne tilganger og sin egen RLS, så hvert ekstra skjema er mer overflate å forsvare. Hold listen kort, og sjekk den først.

Jeg har bygget en gratis [Supabase-sikkerhetssjekk](https://madsalt.tech/no/tools/supabase-security-check/), og listen Exposed schemas er en av de første tingene den leser. Når noen spør hvor trygt et Supabase-prosjekt er, er det her jeg begynner.

## Hva betyr "exposed schemas" i Supabase Data API?

Supabase serverer databasen din over REST med PostgREST. PostgREST svarer bare for skjemaene i `db_schema`-listen sin, og den redigerer du i Dashboard under Project Settings → Data API → Exposed schemas. I prosjektkonfigurasjonen jeg så på, var verdien `public,graphql_public`, og Supabases [veiledning om custom schemas](https://supabase.com/docs/guides/api/using-custom-schemas) sier at `public` er eksponert som standard. En forespørsel om et skjema utenfor listen blir avvist, og [PostgREST](https://docs.postgrest.org/en/stable/references/api/schemas.html) tillater aldri `pg_catalog` eller `information_schema` i den.

## Hvorfor spiller listen noen rolle?

Alt i et eksponert skjema kan nås med den offentlige nøkkelen: tabeller, views og funksjoner. Supabases [RLS-guide](https://supabase.com/docs/guides/database/postgres/row-level-security) er tydelig på det: en tabell i et eksponert skjema uten RLS kan leses og skrives av enhver rolle som har en tilgang til den. Et skjema som ikke står på listen, kan ikke nås gjennom API-et i det hele tatt.

Så et ekstra skjema er ikke en nøytral endring. Legg til `storage` eller `vault` i listen, og du har lagt interne tabeller innenfor rekkevidden til Data API-et. Legg til ditt eget skjema, og hver tabell i det krever samme omtanke som `public`.

![Hva et ekstra exposed schema åpner for. Én anon-forespørsel før og etter at listen er trimmet. Før: et ekstra skjema er exposed: anon-spørring → Data API → ekstra skjema → tabell uten RLS kan leses; Etter: bare public og graphql_public: anon-spørring → Data API → bare standardskjemaer → RLS på alle tabeller.](https://madsalt.tech/charts/no/supabase-exposed-schemas.svg)

*Fra reglene i Supabase-sjekken og Supabases Data API-dokumentasjon, 22. oktober 2026.*

## Hvordan vurderer sjekken ekstra skjemaer?

Sjekken heter `extra_exposed_schemas`. Alt unntatt `public` og `graphql_public` regnes som ekstra, og deretter gjelder:

- Et internt Supabase-skjema på listen (`auth`, `storage`, `realtime`, `vault`, `extensions` og lignende) er en **feil med høy alvorlighet**.
- Bare egne skjemaer, for eksempel `api`, gir en **advarsel med middels alvorlighet**.
- Ingen ekstra skjemaer gir bestått.

Den samme listen styrer andre sjekker. Tabeller med RLS slått av, skrivetilganger for anon, policyer som alltid er sanne, views uten `security_invoker` og `SECURITY DEFINER`-funksjoner som anon kan kalle, blir bare rapportert for eksponerte skjemaer, fordi det er der den offentlige nøkkelen når dem.

## Hvordan bruker du et eget skjema trygt?

Et eget skjema er et legitimt mønster: Supabases guide [Securing your API](https://supabase.com/docs/guides/api/securing-your-api) beskriver et dedikert skjema som `api` som en måte å gjøre den eksponerte flaten lettere å identifisere og gjennomgå, mens interne tabeller blir værende i skjemaer som ikke er eksponert. To steg får det til å fungere, og [veiledningen om custom schemas](https://supabase.com/docs/guides/api/using-custom-schemas) beskriver begge: legg skjemaet til i Exposed schemas, og gi deretter `usage` på det til `anon`, `authenticated` og `service_role`, pluss tilganger på objektene i det.

Eksempelet i veiledningen gir `ALL` på hver tabell. Den linjen ville jeg ikke kopiert som den står. Guiden Securing your API sier at hver rolle bare skal få det minste den trenger, og at du skal aktivere RLS på hver tabell du eksponerer. Tilganger avgjør om en rolle i det hele tatt kan røre en tabell, policyer avgjør hvilke rader.

En separat endring: Supabase [slutter å gi Data API-et automatisk tilgang til nye `public`-tabeller](https://supabase.com/changelog/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically). Det ble standard for nye prosjekter fra 30. mai 2026 og blir innført for eksisterende prosjekter 30. oktober 2026, og eksisterende tabeller beholder tilgangene sine. Det er tilgangslaget. Det endrer ikke hvilke skjemaer som står på listen.

## Hvordan sjekker du hvor trygt ditt eget Supabase-prosjekt er?

Åpne Project Settings → Data API, og les Exposed schemas. Hvis det står mer enn `public` og `graphql_public`, spør hva hvert ekstra skjema brukes til.

List deretter tabellene i disse skjemaene som har RLS slått av, og om `anon` allerede kan lese dem:

```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;
```

Jeg kjørte den på en midlertidig Postgres 17 med et `api`-skjema med én tabell med RLS og én uten, pluss en `public`-tabell uten RLS. Den returnerte bare de to uten:

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

Hver rad der `anon_can_select` er sann, er en tabell som alle med den offentlige nøkkelen din kan lese, helt til du aktiverer RLS eller trekker tilbake tilgangen. Spørringen dekker bare tabeller. Views og funksjoner må sjekkes hver for seg, og det går [sikkerhetsjekklisten min for Lovable-apper](https://madsalt.tech/no/blog/lovable-app-security-checklist/) gjennom, mens [hvordan jeg tester Supabase RLS](https://madsalt.tech/no/blog/how-to-test-supabase-rls/) viser hvordan du beviser at policyene virker.
