# Quickstart: your first project in 5 minutes

> Create a SupaHost project, copy its URL and keys, make a table with Row Level Security in Studio, then read and write it from JavaScript and sign up your first user.

Source: https://supahost.app/docs/getting-started/quickstart · Updated 2026-11-11

This guide takes you from an empty instance to a working table you can query from code. It uses a small recipe app as the example. You need a SupaHost account with an instance; if you don't have one yet, start the 7-day trial at [supahost.app](https://supahost.app) and choose a region close to your users (it can't be changed later).

## 1. Create a project

1. In the dashboard, open **Projects** and click **New project**.
2. Enter a name. Names are 2 to 30 characters of lowercase letters, digits and hyphens, for example `app-one`. The name becomes your project URL: `https://app-one.acme.supahost.space` if your instance is called `acme`.
3. Create the project. It uses the **Blank** template, an empty Supabase project.

The project shows as provisioning for a short while, and you get an email when it is ready. During the trial you can have up to 3 projects.

## 2. Copy the URL and keys

Open the project and go to the **Connect** tab, then **App**. You'll see three values:

| Value | Label | Where it goes |
|---|---|---|
| Project URL | | Every client |
| `anon` key | public | Browser and mobile apps. Safe to ship, because Row Level Security decides what it can do. |
| `service_role` key | secret (click **Reveal**) | Servers only. It bypasses Row Level Security. |

Put them in environment variables rather than in your code:

```bash
SUPABASE_URL=https://app-one.acme.supahost.space
SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIs...
```

The Overview tab also has a ready-made `.env` block you can copy.

## 3. Create a table

Click **Studio** in the project header to open Supabase Studio. The first open takes about 20 seconds while Studio starts. Go to the **SQL editor** and run:

```sql
create table public.recipes (
  id bigint generated always as identity primary key,
  title text not null,
  minutes int,
  user_id uuid references auth.users (id) default auth.uid(),
  created_at timestamptz not null default now()
);

alter table public.recipes enable row level security;

grant select on public.recipes to anon, authenticated;
grant insert on public.recipes to authenticated;

create policy "Anyone can read recipes"
  on public.recipes for select
  to anon, authenticated
  using (true);

create policy "Signed-in users add their own recipes"
  on public.recipes for insert
  to authenticated
  with check ((select auth.uid()) = user_id);

insert into public.recipes (title, minutes)
values ('Tomato soup', 25), ('Flatbread', 40);
```

Row Level Security is what makes the public `anon` key safe. With RLS on and no policy, nobody can read the table through the API. The two policies above let anyone read recipes and let signed-in users add recipes that belong to them. Read [Row Level Security](/docs/database/row-level-security) before you put real data in a table.

## 4. Read the data

From a terminal, with your variables exported:

```bash
curl "$SUPABASE_URL/rest/v1/recipes?select=id,title,minutes" \
  -H "apikey: $SUPABASE_ANON_KEY"
```

From JavaScript, install the client:

```bash
npm install @supabase/supabase-js
```

```ts
// recipes.ts
import { createClient } from '@supabase/supabase-js'

const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!)

const { data, error } = await supabase
  .from('recipes')
  .select('id, title, minutes')
  .order('minutes')

if (error) throw error
console.log(data)
// [ { id: 1, title: 'Tomato soup', minutes: 25 }, { id: 2, title: 'Flatbread', minutes: 40 } ]
```

## 5. Sign up a user and write a row

Auth works out of the box with email and password. By default new users must confirm their email first. To try things quickly, go to the **Auth** tab, open **Sign-in & security**, turn on **Skip email confirmation**, and click **Save sign-in settings**. Changes apply within about a minute. Turn it back off before you launch.

```ts
const { error: signUpError } = await supabase.auth.signUp({
  email: 'cook@example.com',
  password: 'a-long-test-password',
})
if (signUpError) throw signUpError

const { data: recipe, error } = await supabase
  .from('recipes')
  .insert({ title: 'Lemon rice', minutes: 30 })
  .select()
  .single()

console.log(recipe, error)
```

The insert works because the client now sends the user's access token, and the column default fills `user_id` with `auth.uid()`. Try the same insert without signing in and you get a Row Level Security error instead.

When you keep email confirmation on, set the **Site URL** and **Redirect URLs** on the Auth tab so confirmation links send people back to your app. See [Site URL and redirect URLs](/docs/auth/redirect-urls).

## 6. Connect an AI agent (optional)

If you use Claude Code, Cursor or another MCP client, the **AI agents (MCP)** page in the dashboard creates a token and a config snippet so the agent can list tables, run SQL and apply migrations in your project. See [The SupaHost MCP server](/docs/ai-tools/mcp).

## Next steps

- Pick your framework: [Next.js](/docs/getting-started/nextjs), [React](/docs/getting-started/react), [Vue](/docs/getting-started/vue), [SvelteKit](/docs/getting-started/sveltekit), [Flutter](/docs/getting-started/flutter), [Python](/docs/getting-started/python) and others in this section
- [Tables, columns and data](/docs/database/tables)
- [Email and password sign-in](/docs/auth/passwords)
- [Supabase features on SupaHost](/docs/getting-started/feature-support)
