---
id: 'debugging-performance'
title: 'Debugging performance issues'
description: 'Debug slow-running queries using the Postgres execution planner.'
subtitle: 'Debug slow-running queries using the Postgres execution planner.'
---

`explain()` is a method that provides the Postgres `EXPLAIN` execution plan of a query. It is a powerful tool for debugging slow queries and understanding how Postgres will execute a given query. This feature is applicable to any query, including those made through `rpc()` or write operations.

## Enabling `explain()`

`explain()` is disabled by default to protect sensitive information about your database structure and operations. We recommend using `explain()` in a non-production environment. Run the following SQL to enable `explain()`:

{/* prettier-ignore */}
```sql
-- enable explain
alter role authenticator
set pgrst.db_plan_enabled to 'true';

-- reload the config
notify pgrst, 'reload config';
```

## Using `explain()`

To get the execution plan of a query, you can chain the `explain()` method to a Supabase query:

{/* prettier-ignore */}
```ts
const { data, error } = await supabase
  .from('instruments')
  .select()
  .explain()
```

### Example data

To illustrate, consider the following setup of a `instruments` table:

{/* prettier-ignore */}
```sql
create table instruments (
  id int8 primary key,
  name text
);

insert into books
  (id, name)
values
  (1, 'violin'),
  (2, 'viola'),
  (3, 'cello');
```

### Expected response

The response would typically look like this:

{/* prettier-ignore */}
```markdown
Aggregate  (cost=33.34..33.36 rows=1 width=112)
  ->  Limit  (cost=0.00..18.33 rows=1000 width=40)
        ->  Seq Scan on instruments  (cost=0.00..22.00 rows=1200 width=40)
```

By default, the execution plan is returned in TEXT format. However, you can also retrieve it as JSON by specifying the `format` parameter.

## Production use with pre-request protection

If you need to enable `explain()` in a production environment, ensure you protect your database by restricting access to the `explain()` feature. You can do so by using a pre-request function that filters requests based on the IP address:

{/* prettier-ignore */}
```sql
create or replace function filter_plan_requests()
returns void as $$
declare
  headers   json := current_setting('request.headers', true)::json;
  client_ip text := coalesce(headers->>'cf-connecting-ip', '');
  accept    text := coalesce(headers->>'accept', '');
  your_ip   text := '123.123.123.123'; -- replace this with your IP
begin
  if accept like 'application/vnd.pgrst.plan%' and client_ip != your_ip then
    raise insufficient_privilege using
      message = 'Not allowed to use application/vnd.pgrst.plan';
  end if;
end; $$ language plpgsql;
alter role authenticator set pgrst.db_pre_request to 'filter_plan_requests';
notify pgrst, 'reload config';
```

<$Partial path="db_pre_request_warning.mdx" />

Replace `'123.123.123.123'` with your actual IP address.

## Disabling explain

To disable the `explain()` method after use, execute the following SQL commands:

{/* prettier-ignore */}
```sql
-- disable explain
alter role authenticator
set pgrst.db_plan_enabled to 'false';

-- if you used the above pre-request
alter role authenticator
set pgrst.db_pre_request to '';

-- reload the config
notify pgrst, 'reload config';
```
