---
id: functions
title: Database Functions
description: Creating and using Postgres functions.
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';


Postgres has built-in support for [SQL functions](https://www.postgresql.org/docs/current/sql-createfunction.html). 
These functions live inside your database, and they can be [used with the API](/docs/reference/javascript/rpc).

## Quick demo

<iframe
  className="w-full video-with-border"
  width="640"
  height="385"
  src="https://www.youtube-nocookie.com/embed/MJZCCpCYEqk"
  frameBorder="1"
  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
  allowFullScreen
></iframe>

## Getting started

Supabase provides several options for creating database functions. You can use the Dashboard or create them directly using SQL. 
We provide a SQL editor within the Dashboard, or you can [connect](/docs/guides/database/connecting/connecting-to-postgres) to your database 
and run the SQL queries yourself.


1. Go to the "SQL editor" section.
2. Click "New Query".
3. Enter the SQL to create or replace your Database function.
4. Click "Run" or cmd+enter (ctrl+enter).


## Simple Functions

Let's create a basic Database Function which returns a string "hello world".

```sql
create or replace function hello_world() -- 1
returns text -- 2
language sql -- 3
as $$  -- 4
  select 'hello world';  -- 5
$$; --6

```

<details>
<summary>Show/Hide Details</summary>
  
At it's most basic a function has the following parts:

1. `create or replace function hello_world()`: The function declaration, where `hello_world` is the name of the function. You can use either `create` when creating a new function or `replace` when replacing an existing function. Or you can use `create or replace` together to handle either.
2. `returns text`: The type of data that the function returns. If it returns nothing, you can `returns void`. 
3. `language sql`: The language used inside the function body. This can also be a procedural language: `plpgsql`, `plv8`, `plpython`, etc.
4. `as $$`: The function wrapper. Anything enclosed inside the `$$` symbols will be part of the function body.
5. `select 'hello world';`: A simple function body. The final `select` statement inside a function body will be returned if there are no statements following it.
6. `$$;`: The closing symbols of the function wrapper.

</details>

<br />

After the Function is created, we have several ways of "executing" the function - either directly inside the database using SQL, or with one of the client libraries.

<Tabs
defaultValue="SQL"
values={[
  {label: 'SQL', value: 'SQL'},
  {label: 'JS', value: 'JS'},
  {label: 'Dart', value: 'Dart'},
]}>

<TabItem value="SQL">

```sql
select hello_world();
```

</TabItem>
<TabItem value="JS">

```js 
const { data, error } = await supabase
  .rpc('hello_world')
```

Reference: [rpc()](/docs/reference/javascript/rpc)

</TabItem>
<TabItem value="Dart">

```dart 
final res = await supabase
  .rpc('hello_world')
  .execute();
```

Reference: [rpc()](/docs/reference/dart/rpc)

</TabItem>

</Tabs>


## Returning data sets

Database Functions can also return data sets from [Tables](/docs/guides/database/tables) or Views.

For example, if we had a database with some Star Wars data inside:

<Tabs
defaultValue="Data"
values={[
  {label: 'Data', value: 'Data'},
  {label: 'SQL', value: 'SQL'},
]}>

<TabItem value="SQL">

```sql
create table planets (
  id serial primary key,
  name text
);

insert into planets (id, name) 
values 
  (1, 'Tattoine'),
  (2, 'Alderaan'),
  (3, 'Kashyyyk');

create table people (
  id serial primary key,
  name text,
  planet_id bigint references planets
);

insert into people (id, name, planet_id) 
values 
  (1, 'Anakin Skywalker', 1),
  (2, 'Luke Skywalker', 1),
  (3, 'Princess Leia', 2),
  (4, 'Chewbacca', 3);
```

</TabItem>
<TabItem value="Data">

<h4>Planets</h4>

| id    | name | 
| ----  | ---- | 
|    1 | Tattoine | 
|    2 | Alderaan  | 
|    3 | Kashyyyk | 

<h4>People</h4>

| id    | name | planet_id |
| ----  | ---- | ---- | 
|    1 | Anakin Skywalker | 1 | 
|    2 | Luke Skywalker  | 1 | 
|    3 | Princess Leia | 2 | 
|    4 | Chewbacca | 3 | 

</TabItem>

</Tabs>


We could create a function which returns all the planets:

```sql
create or replace function get_planets() 
returns setof planets
language sql
as $$
  select * from planets;
$$;
```

Because this function returns a table set, we can also apply filters and selectors. For example, if we only wanted the first planet:

<Tabs
defaultValue="SQL"
values={[
  {label: 'SQL', value: 'SQL'},
  {label: 'JS', value: 'JS'},
  {label: 'Dart', value: 'Dart'},
]}>

<TabItem value="SQL">

```sql
select *
from get_planets()
where id = 1;
```

</TabItem>
<TabItem value="JS">

```js 
const { data, error } = supabase
  .rpc('get_planets')
  .eq('id', 1)
```

</TabItem>
<TabItem value="Dart">

```dart 
final res = await supabase
  .rpc('get_planets')
  .eq('id', 1)
  .execute();
```

</TabItem>

</Tabs>


## Passing parameters

Let's create a Function to insert a new planet into the `planets` table and return the new ID. Note that this time we're using the `plpgsql` language.

```sql
create or replace function add_planet(name text) 
returns bigint
language plpgsql
as $$
declare 
  new_row bigint;
begin
  insert into planets(name)
  values (add_planet.name)
  returning id into new_row;

  return new_row;
end;
$$;
```

Once again, you can execute this function either inside your database using a `select` query, or with the client libraries:

<Tabs
defaultValue="SQL"
values={[
  {label: 'SQL', value: 'SQL'},
  {label: 'JS', value: 'JS'},
  {label: 'Dart', value: 'Dart'},
]}>

<TabItem value="SQL">

```sql
select * from add_planet('Jakku');
```

</TabItem>
<TabItem value="JS">

```js 
const { data, error } = await supabase
  .rpc('add_planet', { name: 'Jakku' })
```


</TabItem>
<TabItem value="Dart">

```dart 
final res = await supabase
  .rpc('add_planet', params: { 'name': 'Jakku' })
  .execute();
```

</TabItem>

</Tabs>


## Suggestions

### Database Functions vs Edge Functions

For data-intensive operations we recommend using [Database Functions](/docs/guides/database/functions), which are executed within your database
and can be called remotely using the [REST and GraphQL API](/docs/guides/database/api).

For use-cases which require low-latency we recommend [Edge Functions](/docs/guides/functions), which are globally-distributed and can be written in Typescript.

### Security `definer` vs `invoker`

Postgres allows you to specify whether you want the function to be executed as the user _calling_ the function (`invoker`), or as the _creator_ of the function (`definer`). For example:

```sql
create function hello_world() 
returns text 
language plpgsql 
security definer set search_path = public
as $$
begin
  select 'hello world';
end;
$$;
```

It is best practice to use `security invoker` (which is also the default). If you ever use `security definer`, you _must_ set the `search_path`. 
This limits the potential damage if you allow access to schemas which the user executing the function should not have.

## Resources


- Official Client libraries: [JavaScript](/docs/reference/javascript/rpc) and [Dart](/docs/reference/dart/rpc)
- Community client libraries: [github.com/supabase-community](https://github.com/supabase-community)
- PostgreSQL Official Docs: [Chapter 9. Functions and Operators](https://www.postgresql.org/docs/current/functions.html)
- PostgreSQL Reference: [CREATE FUNCTION](https://www.postgresql.org/docs/9.1/sql-createfunction.html)

## Deep Dive 

### Create Database Functions

<iframe
  className="w-full video-with-border"
  width="640"
  height="385"
  src="https://www.youtube-nocookie.com/embed/MJZCCpCYEqk"
  frameBorder="1"
  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
  allowFullScreen
></iframe>

### Call Database Functions using JavaScript

<iframe
  className="w-full video-with-border"
  width="640"
  height="385"
  src="https://www.youtube-nocookie.com/embed/I6nnp9AINJk"
  frameBorder="1"
  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
  allowFullScreen
></iframe>

### Using Database Functions to call an external API

<iframe
  className="w-full video-with-border"
  width="640"
  height="385"
  src="https://www.youtube-nocookie.com/embed/rARgrELRCwY"
  frameBorder="1"
  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
  allowFullScreen
></iframe>
