# Using Custom Schemas

You need additional steps to use custom database schemas with data APIs.

By default, your database has a `public` schema which is automatically exposed on data APIs.

## Creating custom schemas

You can create your own custom schema/s by running the following SQL, substituting `myschema` with the name you want to use for your schema:

```sql
CREATE SCHEMA myschema;
```

## Exposing custom schemas

You can expose custom database schemas - to do so you need to follow these steps:

1. Go to [API settings](/dashboard/project/_/settings/api) and add your custom schema to "Exposed schemas".
2. Run the following SQL, substituting `myschema` with your schema name:

```sql
GRANT USAGE ON SCHEMA myschema TO anon, authenticated, service_role;
GRANT ALL ON ALL TABLES IN SCHEMA myschema TO anon, authenticated, service_role;
GRANT ALL ON ALL ROUTINES IN SCHEMA myschema TO anon, authenticated, service_role;
GRANT ALL ON ALL SEQUENCES IN SCHEMA myschema TO anon, authenticated, service_role;
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA myschema GRANT ALL ON TABLES TO anon, authenticated, service_role;
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA myschema GRANT ALL ON ROUTINES TO anon, authenticated, service_role;
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA myschema GRANT ALL ON SEQUENCES TO anon, authenticated, service_role;
```

Now you can access these schemas from data APIs:

**JavaScript**

```js
// Initialize the JS client
import { createClient } from '@supabase/supabase-js'

const supabase = createClient(SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY, {
  db: { schema: 'myschema' },
})

// Make a request
const { data: todos, error } = await supabase.from('todos').select('*')

// You can also change the target schema on a per-query basis
const { data: todos, error } = await supabase.schema('myschema').from('todos').select('*')
```

Note: With generated `Database` types that include `public`, `createClient<Database>(...)` type-checks `db.schema` against `public` only, unless the schema name is also passed as the second generic: `createClient<Database, 'myschema'>(...)`. `supabase.schema('myschema').from(...)` infers its schema per call and needs no second generic. In both cases `myschema` has to be present in the generated `Database` type.

**Dart**

```dart
// Initialize the Flutter client
await Supabase.initialize(
  url: supabaseUrl,
  publishableKey: publishableKey,
  postgrestOptions: const PostgrestClientOptions(schema: 'myschema'),
);
final supabase = Supabase.instance.client;

// Make a request
final data = await supabase.from('todos').select();

// You can also change the target schema on a per-query basis
final data = await supabase.schema('myschema').from('todos').select();

```

**C#**

```c#
// Initialize the client with a custom schema
var supabase = new Supabase.Client(
  SUPABASE_URL,
  SUPABASE_PUBLISHABLE_KEY,
  new SupabaseOptions { Schema = "myschema" }
);
await supabase.InitializeAsync();

// Make a request
var todos = await supabase.From<Todo>().Get();
```

**cURL**

```bash
# Append /rest/v1/ to your URL, and then use the table name as the route.

# for GET or HEAD request use Accept-Profile
curl '<SUPABASE_URL>/rest/v1/todos' \
  -H "apikey: <SUPABASE_PUBLISHABLE_KEY>" \
  -H "Authorization: Bearer <SUPABASE_PUBLISHABLE_KEY>" \
  -H "Accept-Profile: myschema"

# for POST, PATCH, PUT and DELETE Request use Content-Profile
curl -X POST '<SUPABASE_URL>/rest/v1/todos' \
  -H "apikey: <SUPABASE_PUBLISHABLE_KEY>" \
  -H "Authorization: Bearer <SUPABASE_PUBLISHABLE_KEY>" \
  -H "Content-Type: application/json" \
  -H "Content-Profile: myschema" \
  -d '{"column_name": "value"}'
```
