docs: standardize quickstart guides (#48950)

## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Docs update

## What is the new behavior?

- All 19 guides follow one step order: create project → set up database
→ create app → AI tooling → add keys → create client → query data → run
it → go to production. Added _template.mdx with structure requirements;
it is not enforced with a lint check for now - this will be a separate
PR before adding new guides.
- 4 new partials replace copy-pasted blocks (AI tooling, connection
strings, mobile env vars, going to production).
- Error handling: return a message instead of a blank page when a query
fails.
- All guides verified and tested separately - all work as described.
What was fixed: wrong env var names in the Hono sample, a Next.js page
that redirected to login, missing database permissions in Refine and
Hono, and stale file paths and APIs in SvelteKit, Refine, and TanStack.
- Astro, Expo, Python, Laravel, and Rails were live but missing from the
quickstart grid or listing page. Added, with two new icons.

## Quick links for review

Base preview:
https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs

**Quickstart discovery**: new Astro/Expo/Python/Laravel/Rails entries
and icons

- [Docs homepage
grid](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs)
<img width="1998" height="882" alt="CleanShot 2026-08-12 at 12 06 31@2x"
src="https://github.com/user-attachments/assets/942eb7e2-1e85-4b20-a6a7-c2b127d31b2b"
/>


- [Getting started
overview](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started)
<img width="856" height="878" alt="CleanShot 2026-08-12 at 12 13 30@2x"
src="https://github.com/user-attachments/assets/d48091a9-7daf-4796-a521-14116b7479c9"
/>

### New shared files:


**[apps/docs/content/guides/getting-started/quickstarts/_template.mdx](https://github.com/supabase/supabase/blob/e311542913cf8da07f322a7586339d6f5de30c61/apps/docs/content/guides/getting-started/quickstarts/_template.mdx?plain=1)**
A reference contract the other 19 quickstart guides are checked against.
Documents the required frontmatter, the canonical 10-step section order,
every guide's deviation from that order (and why), the direct-Postgres
exception (Laravel/Rails/RedwoodJS/Spring Boot), and the
discovery-surface/icon requirements for adding a new guide. No lint rule
enforces it yet; that's a follow-up PR.


**[apps/docs/content/_partials/quickstart_ai_tooling.mdx](https://github.com/supabase/supabase/blob/e311542913cf8da07f322a7586339d6f5de30c61/apps/docs/content/_partials/quickstart_ai_tooling.mdx?plain=1)**
Example:
[Next.js](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/nextjs#4-set-up-ai-tooling-optional)
→ "Set up AI tooling" section
Shared by all 19 guides: astrojs, expo-react-native, flask, flutter,
hono, ios-swiftui, kotlin, laravel, nextjs, nuxtjs, reactjs, redwoodjs,
refine, ruby-on-rails, solidjs, spring-boot, sveltekit, tanstack, vue


**[apps/docs/content/_partials/quickstart_going_to_production.mdx](https://github.com/supabase/supabase/blob/e311542913cf8da07f322a7586339d6f5de30c61/apps/docs/content/_partials/quickstart_going_to_production.mdx?plain=1)**
Example:
[Next.js](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/nextjs#going-to-production)
→ "Going to production" section
Shared by all 19 guides: same full list as above


**[apps/docs/content/_partials/quickstart_connection_string.mdx](https://github.com/supabase/supabase/blob/e311542913cf8da07f322a7586339d6f5de30c61/apps/docs/content/_partials/quickstart_connection_string.mdx?plain=1)**
Example:
[Laravel](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/laravel#5-set-up-the-postgres-connection-details)
→ connection string setup step
Shared by 3 guides: laravel, ruby-on-rails, spring-boot – the
ORM/backend frameworks that connect directly to Postgres rather than
through the Data API


**[apps/docs/content/_partials/quickstart_mobile_env_note.mdx](https://github.com/supabase/supabase/blob/e311542913cf8da07f322a7586339d6f5de30c61/apps/docs/content/_partials/quickstart_mobile_env_note.mdx?plain=1)**
Example: [iOS
SwiftUI](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/ios-swiftui#get-api-details:~:text=This%20guide%20substitutes%20your%20project%20URL%20and%20key%20directly)
→ environment variables step
Shared by 3 guides: ios-swiftui, flutter, kotlin – note Expo React
Native is mobile too but doesn't use this partial, since it has its own
`EXPO_PUBLIC_` prefix convention inline instead.

## Per guide changes

**[Astro](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/astrojs#9-query-supabase-data-from-astro)**
Typed query error in the server client sample.

**[Expo React
Native](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/expo-react-native#8-query-data-from-the-app)**
Added an `error` state alongside instruments. Also removed the broken
[`--web` verification
path](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/expo-react-native#9-start-the-app):
expo-sqlite needs Metro wasm + COEP/COOP config the guide never had
(CodeRabbit finding).


**[Flask](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/flask#7-create-the-supabase-client)**
Split "Create the Supabase client" and ["Query
data"](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/flask#8-query-data-from-the-app)
into their own steps.


**[Flutter](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/flutter#9-setup-deep-links-optional)**
Reworded the deep-links section; keeps the framework-specific [Android
`INTERNET` permission
subsection](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/flutter#android)
under "Going to production."


**[Hono](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/hono#6-declare-supabase-environment-variables)**
Split into "Install dependencies," "Declare environment variables," "Set
up anonymous sign-ins," and "Query data" as separate steps. Fixes wrong
env var names from the previous sample.

**[iOS
SwiftUI](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/ios-swiftui#8-query-data-from-the-app)**
Added an `isLoading` state so the loading overlay doesn't hang forever
on a successful empty result (CodeRabbit fix).


**[Kotlin](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/kotlin#5-install-dependencies)**
Fixed the Compose compiler plugin declaration: `apply false` was missing
from the app module (CodeRabbit finding).


**[Laravel](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/laravel#5-set-up-the-postgres-connection-details)**
Now uses the shared `quickstart_connection_string.mdx` partial for the
session-pooler/SSL guidance instead of inline copy.


**[Next.js](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/nextjs#6-allow-public-access-to-the-instruments-page)**
New step fixing the page that previously redirected to login. Its
middleware path check is also now segment-aware so it doesn't over-match
paths like `/instruments-private` (CodeRabbit finding).


**[Nuxt](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/nuxtjs#7-create-the-supabase-client)**
"Create the Supabase client" and ["Query
data"](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/nuxtjs#8-query-data-from-the-app)
split out as their own steps.


**[React](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/reactjs#7-create-the-supabase-client)**
Same
client-creation/[query-data](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/reactjs#8-query-data-from-the-app)
split as the other Vite-based guides.


**[RedwoodJS](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/redwoodjs#2-gather-database-connection-strings)**
Expanded into explicit transaction-mode/session-mode connection strings,
Prisma schema, migration, seed, and scaffold steps; fixes stale file
paths and APIs from the previous version.


**[Refine](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/refine#8-allow-writes-to-the-instruments-table)**
New step fixing the missing RLS grants that made the scaffolded
create/edit pages fail.

**[Ruby on
Rails](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/ruby-on-rails#4-set-up-the-postgres-connection-details)**
Now uses `quickstart_connection_string.mdx`; added a [reminder to save
the database
password](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/ruby-on-rails#1-create-a-supabase-project)
before it's needed for the connection string.


**[SolidJS](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/solidjs#7-create-the-supabase-client)**
Same
client-creation/[query-data](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/solidjs#8-query-data-from-the-app)
split, adapted to Solid's `resource.error`.

**[Spring
Boot](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/spring-boot#4-set-up-the-postgres-connection-details)**
Connection-string section now uses the shared partial instead of a
duplicated inline caution.


**[SvelteKit](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/sveltekit#8-query-data-from-the-app)**
Updated `load` functions (both `+page.js` and `+page.server.ts`
variants) with explicit query-error typing; fixes stale file paths and
APIs from the previous version.


**[TanStack](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/tanstack#8-query-supabase-data-from-tanstack-start)**
`fetchInstruments` now returns and renders the query error instead of
silently returning an empty list (CodeRabbit finding); fixes stale file
paths and APIs from the previous version.


**[Vue](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/vue#7-create-the-supabase-client)**
Same
client-creation/[query-data](https://docs-git-docs-standardize-framework-quickstarts-supabase.vercel.app/docs/guides/getting-started/quickstarts/vue#8-query-data-from-the-app)
split as the other Vite-based guides.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added SolidJS, RedwoodJS, Refine, Laravel, and Ruby on Rails
quickstarts.
* Added framework discovery entries for Astro, Expo React Native,
Python, Laravel, and Rails.
* Added optional AI tooling, MCP setup, connection-string, mobile
configuration, and production-readiness guidance.
* Added a Hono authentication example with anonymous sign-in, user
details, and instrument data.

* **Documentation**
* Expanded setup, environment, authentication, RLS, migration, SSL, and
deployment guidance.

* **Bug Fixes**
  * Improved sample error handling for failed data requests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Miranda Limonczenko <miranda.limonczenko@supabase.io>
This commit is contained in:
Illia BasalaievandMiranda Limonczenko authored and GitHub committed 2026-08-14 15:03:37 +02:00
1 parent ebb8e2336e
commit ee1eb5dbca
34 files changed
+1089 -431

No files matched your search

@@ -47,6 +47,21 @@ const frameworks = [
icon: '/docs/img/icons/svelte-icon',
href: '/guides/getting-started/quickstarts/sveltekit',
},
{
name: 'SolidJS',
icon: '/docs/img/icons/solidjs-icon',
href: '/guides/getting-started/quickstarts/solidjs',
},
{
name: 'RedwoodJS',
icon: '/docs/img/icons/redwood-icon',
href: '/guides/getting-started/quickstarts/redwoodjs',
},
{
name: 'Refine',
icon: '/docs/img/icons/refine-icon',
href: '/guides/getting-started/quickstarts/refine',
},
{
name: 'Hono',
icon: '/docs/img/icons/hono-icon',
@@ -81,6 +96,16 @@ const frameworks = [
icon: '/docs/img/icons/python-icon',
href: '/guides/getting-started/quickstarts/flask',
},
{
name: 'Laravel',
icon: '/docs/img/icons/laravel-icon',
href: '/guides/getting-started/quickstarts/laravel',
},
{
name: 'Ruby on Rails',
icon: '/docs/img/icons/rails-icon',
href: '/guides/getting-started/quickstarts/ruby-on-rails',
},
]
export function FrameworkQuickstarts({ labelledBy }: { labelledBy?: string }) {
@@ -0,0 +1,19 @@
Supabase provides two ways to give AI tools context about your project: Agent Skills, which give your AI coding agent procedural knowledge, and the MCP server, which connects AI assistants to your Supabase project directly.
### Agent Skills
[Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
#### Installing Agent Skills
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
### Supabase MCP server
The Supabase MCP server connects AI assistants to Supabase, so they can inspect your schema and act on your projects on your behalf. Find out how to add it to your client in [the MCP docs](/docs/guides/ai-tools/mcp).
@@ -0,0 +1,13 @@
1. Navigate to your project dashboard and click on [Connect](/dashboard/project/_?showConnect=true&connectTab=direct&method=session).
<Admonition type="caution">
Don't use the Transaction pooler (port `6543`) as your app's main data source. Most ORMs rely on server-side prepared statements, which the Transaction pooler doesn't support. Use the Session pooler (port `5432`), or the direct connection string if you're in an [IPv6 environment](/docs/guides/troubleshooting/supabase--your-network-ipv4-and-ipv6-compatibility-cHe3BP) or have the [IPv4 Add-On](/docs/guides/platform/ipv4-address).
</Admonition>
1. Look for the **Session pooler** connection string and copy it. Replace the password placeholder with your saved database password, and [percent-encode](https://en.wikipedia.org/wiki/Percent-encoding) any reserved characters it contains, such as `&`, `#`, `?`, or a space. If you don't have your database password, you can reset it in your [Database Settings](/dashboard/project/_/database/settings).
1. Set `sslmode=require` either on the connection string itself or as an explicit config option if your framework sets it separately. Most drivers default to `prefer`, which falls back to sending your data in plaintext if the encrypted attempt fails. You can also [enforce SSL](/docs/guides/platform/ssl-enforcement) on the database side.
The connection strings below show the format only. Take the host, port, and username from the string you copied rather than typing the bracketed placeholders literally.
@@ -0,0 +1,9 @@
## Production requirements
The quickstart procedure in this guide optimizes for getting you to a working app, not for production.
Before you deploy:
- If your app reads or writes through the Data API, review your [Row Level Security](/docs/guides/database/postgres/row-level-security) policies. Any policy you added here is scoped to this quickstart's sample data, not to real user data.
- Set your Supabase credentials as environment variables on whatever platform you deploy to, rather than committing them to source control.
- Configure a [custom domain](/docs/guides/platform/custom-domains) for your Supabase project once you're ready to go live.
@@ -0,0 +1,5 @@
<Admonition type="note">
This guide substitutes your project URL and key directly into the code above, rather than reading them from a `.env` file. Mobile apps don't get environment variables injected at runtime the way a bundler-based web app does. You'd need a build-time mechanism specific to your toolchain, such as `--dart-define-from-file` for Flutter, an `.xcconfig` file for iOS, or a `Gradle` `BuildConfig` field for Android. That's a good next step once you're past this quickstart, so your keys aren't committed to source control.
</Admonition>
@@ -0,0 +1,154 @@
This file is a reference contract for framework quickstarts in this directory. It is
not a rendered page (filenames starting with `_` are excluded from the docs build
and from `supa-mdx-lint`) — it exists so every quickstart conforms to the same shape,
and so Phase 3's lint rule has a single source to check against.
## Required frontmatter
```yaml
---
title: 'Use Supabase with <Framework>'
subtitle: '<one sentence: what the reader builds>'
breadcrumb: 'Framework Quickstarts'
---
```
## Required section order
Before the numbered steps, and before any heading:
- `<AiPrompt id="<slug>" />` — always first. Every id must exist as a key in
`apps/docs/data/ai-prompts.data.ts`.
- An optional `## Prerequisites` section, for guides whose toolchain isn't implied
by the framework itself. `spring-boot.mdx` is the current example: Java 17,
`curl`, `unzip`. Don't add one to restate the obvious.
The list below is the canonical order, not the literal heading numbers.
`quickstart_db_setup.mdx` supplies headings 1 and 2, so guides that use it start
their own headings at 3. Guides that use `quickstart_create_project.mdx` alone get
heading 1 from the partial and start at 2. A guide may also insert a
framework-specific step — `astrojs.mdx` adds **Configure Astro for SSR** between the
client library and the environment variables — so number each guide's headings
sequentially from where its partial leaves off rather than copying numbers from here.
1. **Create a Supabase project** — via `<$Partial path="quickstart_create_project.mdx" />`,
either directly or nested inside `quickstart_db_setup.mdx` (see below).
- **Set up your database** (also numbered step 2, replacing the above) — only
for guides that query the shared `instruments` sample table through a
Supabase client library. Use `<$Partial path="quickstart_db_setup.mdx" />`
instead (it nests the project-creation partial). Guides that connect
directly to Postgres with their own ORM (Laravel, Rails, RedwoodJS, Spring
Boot) skip this and use `quickstart_create_project.mdx` alone — add a
one-line note stating the guide uses the framework's own tables instead, so
the omission reads as deliberate rather than a gap.
2. **Create a `<framework>` app**
3. **Set up AI tooling (optional)** — `<$Partial path="quickstart_ai_tooling.mdx" />`.
Covers both Agent Skills and the MCP server in one step. Keep them together:
two adjacent optional AI steps push the first real Supabase code further down
the page for no reader benefit, and the prose is identical across all 19 guides,
so it lives in the partial rather than being copied per guide.
4. **Install the Supabase client library**
- Guides that start from a scaffold which already depends on `supabase-js`
keep the step but retitle it to what the reader actually does. `hono.mdx`
uses **Install dependencies**, because `npx supabase bootstrap hono` already
lists the packages in `package.json` and the reader only runs `npm install`.
`nextjs.mdx` drops the step entirely, because the `with-supabase` template
installs them as part of step 3.
5. **Declare Supabase environment variables** — env vars only, never literal
credentials in code. Mobile guides (Flutter, iOS SwiftUI, Kotlin) are the
documented exception — they use `YOUR_SUPABASE_URL` / `YOUR_SUPABASE_PUBLISHABLE_KEY`
placeholder substitution instead of a `.env` file, with
`<$Partial path="quickstart_mobile_env_note.mdx" />` explaining why. Include the
`<Button>` "Open Connect panel" link and `<$Partial path="api_settings.mdx" />`
(or, for direct-Postgres guides, `<$Partial path="quickstart_connection_string.mdx" />`).
6. **Create the Supabase client** — its own step, not inlined into the query
sample. `reactjs.mdx`, `vue.mdx`, `solidjs.mdx`, and `sveltekit.mdx` export a
shared client from `src/lib/supabaseClient.*`; Nuxt uses a composable in
`app/composables/` because `useRuntimeConfig()` requires a Nuxt context.
- Guides whose scaffold already creates the client omit this step rather than
telling the reader to write a file that exists. `nextjs.mdx` (the
`with-supabase` template's `lib/supabase/{client,server}.ts`), `hono.mdx`
(`src/middleware/auth.middleware.ts`), and `refine.mdx` (the
`refine-supabase` preset's `src/providers/supabase-client.ts`) all do this.
When you omit it, say where the client lives at the point the query sample
first imports it. Otherwise the import arrives unexplained, and an agent
reading the page has no signal the file exists.
7. **Query data from the app** — every inline query sample must handle the error
branch. `reactjs.mdx`'s `getInstruments` (destructure `error`, check it, log/render
before touching `data`) is the reference implementation; adapt to the language's
idiom (`try`/`catch` for Kotlin/Flask, `snapshot.hasError` for Flutter's
`FutureBuilder`, Solid's `resource.error`, etc.) rather than copying JS syntax
verbatim.
- If the guide's UI also writes, it must add the matching grants and RLS
policies before telling the reader to try them. `quickstart_db_setup.mdx`
grants `select` to `anon` only, so an insert or update through a Supabase
client library fails with `permission denied for table instruments`.
`refine.mdx` (scaffolded create and edit pages) and `hono.mdx` (anonymous
sign-ins use the `authenticated` role) each carry their own policy step for
this reason. Guides that reach Postgres directly through their own ORM bypass
RLS and don't need one.
8. **Start the app** — exact local URL and what the reader should see.
9. **Production requirements** — `<$Partial path="quickstart_going_to_production.mdx" />`,
which supplies the `##` heading itself, so don't add one in the host file. Every
guide gets this, immediately before Next steps. Its wording is deliberately neutral
about which tables the guide uses, so it stays true for both the `instruments`
guides and the direct-Postgres ones. `flutter.mdx` is the one guide that appends a
framework-specific `###` subsection under it, for the Android `INTERNET`
permission.
10. **Next steps** — canonical order: framework-specific Auth pointer (or the
generic `Set up [Auth](/docs/guides/auth) for your app` if there's no
framework-specific one) → Insert more data → Storage → Supabase Library (`/ui`).
- Only link `/ui` from a framework Supabase Library actually ships blocks for.
The supported list is `supportedFrameworks` in
`apps/ui-library/config/docs.ts`, currently Next.js, Nuxt, React, React
Router, TanStack, and Vue. Check it rather than assuming — Astro, SolidJS,
and SvelteKit are **not** supported, so those guides omit the link even
though they render a component-based frontend.
- `/ui` and `/ui/docs/*` are permanent redirects to `/library` and
`/library/docs/*`. Existing guides still link `/ui`; point new links at
`/library` directly, and use `/library/docs/<framework>/<block>` for
individual blocks.
- Also omit it from mobile-native and backend-only guides, and from RedwoodJS
and Refine, which ship their own component and Inferencer story.
## Direct-Postgres guides (Laravel, Rails, RedwoodJS, Spring Boot)
Use `<$Partial path="quickstart_connection_string.mdx" />` for the session-pooler
rationale, IPv6/IPv4 note, percent-encoding, and `sslmode` guidance. Laravel, Rails,
and Spring Boot all use it. Keep the actual connection-string code block in the host
file — the URI format differs (`postgres://` vs `jdbc:postgresql://`).
RedwoodJS is the exception and doesn't use the partial: Prisma needs a Transaction-mode
string for app queries and a Session-mode string for migrations, so the guide walks
through both connection modes itself rather than the single session-pooler string the
partial describes.
## Discovery surfaces
A new quickstart must appear in the navigation menu, and optionally in the content
listing and the framework grid:
- `apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts` — required
- `apps/docs/data/content-listings/getting-started.data.ts` — optional
- `apps/docs/components/FrameworkQuickstarts.tsx` — optional
Both optional surfaces need an icon in `apps/docs/public/img/icons/`, so a guide stays
out of them until the framework's icon is one Supabase can use. Spring Boot is the
current example. The content listing also accepts an icon chip
(`{ kind: 'server', color: '#64748B', bg: 'rgba(100,116,139,0.1)' }`) in place of a
brand icon.
Icons must be square and readable on both themes. `FrameworkQuickstarts.tsx` renders
them at a fixed width in a `bg-surface-100` tile, so a wide wordmark renders small and
an icon with no explicit `fill` defaults to black and disappears in dark mode. Set the
brand color explicitly, and pad the `viewBox` to a square if the source asset isn't
one. Icons that ship a `-light.svg` variant set `hasLightIcon: true`, which uses the
light file in light mode and the base file in dark mode.
## What's deliberately not in this contract yet
- A machine-checked version of this list (Phase 3 — a `supa-mdx-lint` rule or a
vitest over the MDX AST).
- A "last verified" date, pinned framework versions, or a time-to-value label per
guide (Phase 4).
@@ -17,17 +17,9 @@ npm create astro@latest my-app
cd my-app
```
## 4. Install Supabase's Agent Skills (optional)
## 4. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
<$Partial path="quickstart_ai_tooling.mdx" />
## 5. Install Supabase client library and Node adapter
@@ -96,7 +88,7 @@ This queries all rows from the `instruments` table you created earlier and rende
import { createServerClient } from "../lib/supabase";
const supabase = createServerClient();
const { data: instruments } = await supabase.from("instruments").select();
const { data: instruments, error } = await supabase.from("instruments").select();
---
<html>
@@ -104,11 +96,15 @@ const { data: instruments } = await supabase.from("instruments").select();
<title>Instruments</title>
</head>
<body>
<ul>
{instruments?.map((instrument) => (
<li>{instrument.name}</li>
))}
</ul>
{error ? (
<p>Error loading instruments: {error.message}</p>
) : (
<ul>
{instruments?.map((instrument) => (
<li>{instrument.name}</li>
))}
</ul>
)}
</body>
</html>
```
@@ -121,9 +117,10 @@ Run the development server, go to http://localhost:4321/instruments in your brow
npm run dev
```
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Explore [drop-in UI components](/ui) for your Supabase app
- Set up [Auth](/docs/guides/auth) for your app
- [Insert more data](/docs/guides/database/import-data) into your database
- Upload and serve static files using [Storage](/docs/guides/storage)
@@ -16,17 +16,9 @@ Create a minimal Expo app using the `create-expo-app` command with the blank Typ
npx create-expo-app my-app --template blank-typescript
```
## 4. Install Supabase's Agent Skills (optional)
## 4. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
<$Partial path="quickstart_ai_tooling.mdx" />
## 5. Install the Supabase client library
@@ -70,8 +62,8 @@ import { createClient } from '@supabase/supabase-js'
import 'expo-sqlite/localStorage/install'
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL
const supabasePublishableKey = process.env.EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL!
const supabasePublishableKey = process.env.EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
export const supabase = createClient(supabaseUrl, supabasePublishableKey, {
auth: {
@@ -95,16 +87,36 @@ import { FlatList, StyleSheet, Text, View } from 'react-native'
import { supabase } from './lib/supabase'
type Instrument = {
id: number
name: string
}
export default function App() {
const [instruments, setInstruments] = useState([])
const [instruments, setInstruments] = useState<Instrument[]>([])
const [error, setError] = useState<string | null>(null)
useEffect(() => {
getInstruments()
}, [])
async function getInstruments() {
const { data } = await supabase.from('instruments').select()
setInstruments(data)
const { data, error } = await supabase.from('instruments').select()
if (error) {
setError(error.message)
return
}
setInstruments(data ?? [])
}
if (error) {
return (
<View style={styles.container}>
<Text>Error loading instruments: {error}</Text>
</View>
)
}
return (
@@ -141,6 +153,8 @@ Run the development server and scan the QR code with the Expo Go app on your pho
npx expo start
```
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Set up [Auth](/docs/guides/auth) for your app
@@ -18,17 +18,9 @@ python3 -m venv venv
source venv/bin/activate
```
## 4. Install Supabase's Agent Skills (optional)
## 4. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
<$Partial path="quickstart_ai_tooling.mdx" />
## 5. Install Flask and the Supabase client library
@@ -57,7 +49,7 @@ SUPABASE_PUBLISHABLE_KEY=<SUBSTITUTE_SUPABASE_PUBLISHABLE_KEY>
<$Partial path="api_settings.mdx" variables={{ "framework": "flask", "tab": "frameworks" }} />
## 7. Query data from the app
## 7. Create the Supabase client
Install the `python-dotenv` package to load environment variables:
@@ -65,12 +57,13 @@ Install the `python-dotenv` package to load environment variables:
pip install python-dotenv
```
Create an `app.py` file and add a route that fetches data from your `instruments` table using the Supabase client.
Create an `app.py` file and initialize the Flask app and the Supabase client from your environment variables.
```python name=app.py
import os
from flask import Flask
from supabase import create_client, Client
from postgrest import APIError
from dotenv import load_dotenv
load_dotenv()
@@ -81,10 +74,20 @@ supabase: Client = create_client(
os.environ.get("SUPABASE_URL"),
os.environ.get("SUPABASE_PUBLISHABLE_KEY")
)
```
## 8. Query data from the app
Add a route to `app.py` that fetches data from your `instruments` table.
```python name=app.py
@app.route('/')
def index():
response = supabase.table('instruments').select("*").execute()
try:
response = supabase.table('instruments').select("*").execute()
except APIError as error:
return f'<p>Error loading instruments: {error.message}</p>'
instruments = response.data
html = '<h1>Instruments</h1><ul>'
@@ -98,7 +101,7 @@ if __name__ == '__main__':
app.run(debug=True)
```
## 8. Start the app
## 9. Start the app
Run the Flask development server, and go to http://localhost:5000 in your browser, you should see the list of instruments.
@@ -106,6 +109,14 @@ Run the Flask development server, and go to http://localhost:5000 in your browse
python app.py
```
<Admonition type="note">
On macOS, port 5000 is used by the AirPlay Receiver service. If the page doesn't load, turn AirPlay Receiver off in **System Settings > General > AirDrop & Handoff**, or run the app on another port with `app.run(debug=True, port=5001)`.
</Admonition>
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Set up [Auth](/docs/guides/auth) for your app
@@ -16,17 +16,9 @@ Create a Flutter app using the `flutter create` command.
flutter create my_app
```
## 4. Install Supabase's Agent Skills (optional)
## 4. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
<$Partial path="quickstart_ai_tooling.mdx" />
## 5. Install the Supabase client library
@@ -64,6 +56,8 @@ Future<void> main() async {
<$Partial path="api_settings.mdx" variables={{ "framework": "flutter", "tab": "mobiles" }} />
<$Partial path="quickstart_mobile_env_note.mdx" />
## 7. Query data from the app
Use a `FutureBuilder` to fetch the data when the home page loads and display the query result in a `ListView`.
@@ -101,6 +95,9 @@ class _HomePageState extends State<HomePage> {
body: FutureBuilder(
future: _future,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(child: Text('Error loading instruments: ${snapshot.error}'));
}
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
@@ -136,7 +133,7 @@ flutter run
Many sign in methods require deep links to redirect the user back to your app after authentication. Read more about setting deep links up for all platforms (including web) in the [Flutter Mobile Guide](/docs/guides/getting-started/tutorials/with-flutter#setup-deep-links).
## Going to production
<$Partial path="quickstart_going_to_production.mdx" />
### Android
@@ -16,19 +16,11 @@ Bootstrap the Hono example app from the Supabase Samples using the CLI.
npx supabase@latest bootstrap hono
```
## 4. Install Supabase's Agent Skills (optional)
## 4. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
<$Partial path="quickstart_ai_tooling.mdx" />
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
## 5. Install the Supabase client library
## 5. Install dependencies
The `package.json` file in the project includes the necessary dependencies, including `@supabase/supabase-js` and `@supabase/ssr` to help with server-side auth.
@@ -36,32 +28,65 @@ The `package.json` file in the project includes the necessary dependencies, incl
npm install
```
## 6. Set up the required environment variables
## 6. Declare Supabase environment variables
Copy the `.env.example` file to `.env` and update the values with your Supabase project URL and publishable key, which you can get from the helper below, or [from the project **Connect** panel](/dashboard/project/_?showConnect=true&connectTab=frameworks).
Lastly, [enable anonymous sign-ins](/dashboard/project/_/auth/providers) in the Auth settings.
Copy the `.env.example` file to `.env`.
```bash
cp .env.example .env
```
Update the values with your Supabase project URL and publishable key, which you can get from the helper below, or [from the project **Connect** panel](/dashboard/project/_?showConnect=true&connectTab=frameworks).
<Button variant="primary" asChild>
<a href="/dashboard/project/_?showConnect=true">Open Connect panel</a>
</Button>
<$Partial path="api_settings.mdx" variables={{ "framework": "", "tab": "" }} />
## 7. Start the app
## 7. Set up anonymous sign-ins
Start the app, go to http://localhost:5173.
This app signs users in anonymously, so [enable anonymous sign-ins](/dashboard/project/_/auth/providers) in the Auth settings.
Learn how [server side auth](/docs/guides/auth/server-side/creating-a-client?queryGroups=framework&framework=hono) works with Hono.
Anonymous sign-ins use the `authenticated` role, but the database setup in step 2 grants read access to the `anon` role only. Without the privilege and a matching policy for `authenticated`, the instruments query returns no rows. Run the following in the [SQL Editor](/dashboard/project/_/sql/new) to grant the privilege and add the policy:
```sql SQL_EDITOR
grant select on public.instruments to authenticated;
create policy "authenticated can read instruments"
on public.instruments
for select to authenticated
using (true);
```
## 8. Query data from the app
The bootstrapped app already includes the route that reads your `instruments` table, in `src/index.tsx`. The middleware in `src/middleware/auth.middleware.ts` creates a request-scoped Supabase client, so `getSupabase(c)` returns a client that already carries the signed-in user's auth token. Your RLS policies apply to the query.
```tsx name=src/index.tsx
app.get('/instruments', async (c) => {
const supabase = getSupabase(c)
const { data, error } = await supabase.from('instruments').select('*')
if (error) {
console.error(error)
return c.json({ error: error.message }, 500)
}
return c.json(data)
})
```
## 9. Start the app
Start the app, go to http://localhost:5173, sign in anonymously, then open the instruments list.
```bash
npm run dev
```
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Learn how [server side auth](/docs/guides/auth/server-side/creating-a-client?queryGroups=framework&framework=hono) works with Hono.
@@ -12,17 +12,9 @@ breadcrumb: 'Framework Quickstarts'
Select the **Xcode > New Project > iOS > App** menu item.
## 4. Install Supabase's Agent Skills (optional)
## 4. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
<$Partial path="quickstart_ai_tooling.mdx" />
## 5. Install the Supabase client library
@@ -34,7 +26,7 @@ Make sure to add `Supabase` product package as a dependency to your application
## 6. Initialize the Supabase client
Create a new `Supabase.swift` file add a new Supabase instance using your project URL and publishable key, which you can get from the helper below, or [from the project **Connect** panel](/dashboard/project/_?showConnect=true&framework=swift&connectTab=mobiles):
Create a new `Supabase.swift` file and initialize a Supabase client using your project URL and publishable key, which you can get from the helper below, or [from the project **Connect** panel](/dashboard/project/_?showConnect=true&framework=swift&connectTab=mobiles):
<Button variant="primary" asChild>
<a href="/dashboard/project/_?showConnect=true&connectTab=mobiles&framework=swift">
@@ -53,6 +45,8 @@ let supabase = SupabaseClient(
<$Partial path="api_settings.mdx" variables={{ "framework": "swift", "tab": "mobiles" }} />
<$Partial path="quickstart_mobile_env_note.mdx" />
## 7. Create a data model for instruments
Create a decodable struct to deserialize the data from the database.
@@ -78,13 +72,17 @@ import SwiftUI
struct ContentView: View {
@State var instruments: [Instrument] = []
@State var errorMessage: String?
@State var isLoading = true
var body: some View {
List(instruments) { instrument in
Text(instrument.name)
}
.overlay {
if instruments.isEmpty {
if let errorMessage {
Text("Error loading instruments: \(errorMessage)")
} else if isLoading {
ProgressView()
}
}
@@ -92,8 +90,10 @@ struct ContentView: View {
do {
instruments = try await supabase.from("instruments").select().execute().value
} catch {
dump(error)
errorMessage = error.localizedDescription
}
isLoading = false
}
}
}
@@ -107,6 +107,8 @@ Run the app on a simulator or a physical device by hitting `Cmd + R` on Xcode.
If you want to implement authentication features like magic links or OAuth, you need to set up deep links to redirect users back to your app. For instructions on configuring custom URL schemes for your iOS app, see the [deep linking guide](/docs/guides/auth/native-mobile-deep-linking?platform=swift).
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Learn how to build a complete user management app with authentication in the [Swift tutorial](/docs/guides/getting-started/tutorials/with-swift)
@@ -12,27 +12,35 @@ breadcrumb: 'Framework Quickstarts'
Select the **Android Studio > New > New Android Project** menu item.
## 4. Install Supabase's Agent Skills (optional)
## 4. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
<$Partial path="quickstart_ai_tooling.mdx" />
## 5. Install dependencies
Open `build.gradle.kts` (app) file and add the serialization plugin, Ktor client, and Supabase client.
Replace the version placeholders `$kotlin_version` with the Kotlin version of the project, and `$supabase_version` and `$ktor_version` with the respective latest versions.
Replace the version placeholders `$kotlin_version` with the Kotlin version of the project, and `$supabase_version` and `$ktor_version` with the respective latest versions. For example, Kotlin `2.2.21`, supabase-kt BOM `3.5.0`, and Ktor `3.0.3`.
<Admonition type="note">
You can find the latest supabase-kt version [on GitHub](https://github.com/supabase-community/supabase-kt/releases) and Ktor [in the Ktor documentation](https://ktor.io/docs/welcome.html).
If your project uses Kotlin 2.0 or newer with Jetpack Compose, declare the Compose compiler plugin in your root `build.gradle.kts`:
```kotlin
id("org.jetbrains.kotlin.plugin.compose") version "$kotlin_version" apply false
```
Then apply it in the app module, without the version and without `apply false`:
```kotlin
id("org.jetbrains.kotlin.plugin.compose")
```
</Admonition>
<Admonition type="note">
You can find the latest supabase-kt version [on GitHub](https://github.com/supabase-community/supabase-kt/releases) and Ktor [in the Ktor documentation](https://ktor.io/docs/welcome.html). Match your Kotlin version to the supabase-kt release requirements.
</Admonition>
@@ -75,11 +83,12 @@ Replace the `supabaseUrl` and `supabaseKey` with your own, which you can get fro
</Button>
```kotlin
import io.github.jan.supabase.postgrest.from
import ...
val supabase = createSupabaseClient(
supabaseUrl = "https://xyzcompany.supabase.co",
supabaseKey = "your_publishable_key"
supabaseUrl = "YOUR_SUPABASE_URL",
supabaseKey = "YOUR_SUPABASE_PUBLISHABLE_KEY"
) {
install(Postgrest)
}
@@ -88,6 +97,8 @@ val supabase = createSupabaseClient(
<$Partial path="api_settings.mdx" variables={{ "framework": "androidkotlin", "tab": "mobiles" }} />
<$Partial path="quickstart_mobile_env_note.mdx" />
## 8. Create a data model for instruments
Create a serializable data class to represent the data from the database.
@@ -95,6 +106,8 @@ Create a serializable data class to represent the data from the database.
Add the following below the `createSupabaseClient` function in the `MainActivity.kt` file.
```kotlin
import kotlinx.serialization.Serializable
@Serializable
data class Instrument(
val id: Int,
@@ -114,19 +127,23 @@ This example application makes a network request from the UI code. In production
</Admonition>
<Admonition type="note">
This snippet omits the app-specific theme wrapper that Android Studio generates (named after your project, e.g. `<YourAppName>Theme`), so it compiles regardless of what you named your project. Wrap the `Surface` in your generated theme composable from `ui/theme/Theme.kt` if you want your project's Material theme applied.
</Admonition>
```kotlin
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
SupabaseTutorialTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
InstrumentsList()
}
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
InstrumentsList()
}
}
}
@@ -135,12 +152,24 @@ class MainActivity : ComponentActivity() {
@Composable
fun InstrumentsList() {
var instruments by remember { mutableStateOf<List<Instrument>>(listOf()) }
var error by remember { mutableStateOf<String?>(null) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
instruments = supabase.from("instruments")
.select().decodeList<Instrument>()
try {
instruments = supabase.from("instruments")
.select().decodeList<Instrument>()
} catch (e: Exception) {
error = e.message
}
}
}
if (error != null) {
Text(
"Error loading instruments: $error",
modifier = Modifier.padding(8.dp),
)
return
}
LazyColumn {
items(
instruments,
@@ -159,6 +188,8 @@ fun InstrumentsList() {
Run the app on an emulator or a physical device by clicking the `Run app` button in Android Studio.
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Learn how to build a complete user management app with authentication in the [Kotlin tutorial](/docs/guides/getting-started/tutorials/with-kotlin)
@@ -6,65 +6,61 @@ breadcrumb: 'Framework Quickstarts'
<AiPrompt id="laravel" />
<$Partial path="quickstart_db_setup.mdx" />
<$Partial path="quickstart_create_project.mdx" />
## 3. Create a Laravel project
Save your database password securely. You need it for the connection string.
<Admonition type="note">
This guide uses Laravel's own database tables (via Breeze and Eloquent), not the shared `instruments` sample table used by other quickstarts.
</Admonition>
## 2. Create a Laravel project
Make sure your PHP and Composer versions are up to date, then use `composer create-project` to scaffold a new Laravel project.
See the [Laravel docs](https://laravel.com/docs/10.x/installation#creating-a-laravel-project) for more details.
See the [Laravel docs](https://laravel.com/docs/12.x/installation#creating-a-laravel-project) for more details.
```bash
composer create-project laravel/laravel example-app
```
## 4. Install Supabase's Agent Skills (optional)
## 3. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
<$Partial path="quickstart_ai_tooling.mdx" />
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
## 4. Install the authentication template
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
## 5. Install the authentication template
Install [Laravel Breeze](https://laravel.com/docs/10.x/starter-kits#laravel-breeze), a basic implementation of all of Laravel's [authentication features](https://laravel.com/docs/10.x/authentication).
Install [Laravel Breeze](https://github.com/laravel/breeze), a basic implementation of all of Laravel's [authentication features](https://laravel.com/docs/12.x/authentication). It ships the migrations that the next step runs against your Supabase database.
```bash
composer require laravel/breeze --dev
php artisan breeze:install
php artisan breeze:install blade
```
## 6. Set up the Postgres connection details
Pass a stack name such as `blade`, `react`, or `vue` when prompted. The example above uses Blade templates.
Navigate to your project dashboard and click on [Connect](/dashboard/project/_?showConnect=true&connectTab=direct&method=session).
## 5. Set up the Postgres connection details
Look for the Session Pooler connection string and copy the string. You will need to replace the Password with your saved database password. You can reset your database password in your [Database Settings](/dashboard/project/_/database/settings) if you do not have it.
<Admonition type="note">
If you're in an [IPv6 environment](https://github.com/orgs/supabase/discussions/27034) or have the IPv4 Add-On, you can use the direct connection string instead of Supavisor in Session mode.
</Admonition>
<$Partial path="quickstart_connection_string.mdx" />
```bash name=.env
DB_CONNECTION=pgsql
DB_URL=postgres://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@aws-[REGION].pooler.supabase.com:5432/postgres
DB_URL=postgres://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@[POOLER-HOST]:5432/postgres
```
## 7. Change the default schema
Laravel sets `sslmode` as an explicit `config/database.php` option rather than a URL parameter. The next step covers this.
## 6. Change the default schema
By default Laravel uses the `public` schema. We recommend changing this as Supabase exposes the `public` schema as a [data API](/docs/guides/api).
You can change the schema of your Laravel application by modifying the `search_path` variable `app/config/database.php`.
You can change the schema of your Laravel application by modifying the `search_path` variable in `config/database.php`.
The schema you specify in `search_path` has to exist on Supabase. You can create a new schema from the [Table Editor](/dashboard/project/_/editor).
```php name=app/config/database.php
```php name=config/database.php
'pgsql' => [
'driver' => 'pgsql',
'url' => env('DB_URL'),
@@ -83,17 +79,21 @@ The schema you specify in `search_path` has to exist on Supabase. You can create
Laravel ships with `sslmode` set to `prefer`, which sends your data in plaintext if the encrypted attempt fails. Set it to `require` so the connection fails instead. You can also [enforce SSL](/docs/guides/platform/ssl-enforcement) on the database side.
## 8. Run the database migrations
## 7. Run the database migrations
Laravel ships with database migration files that set up the required tables for Laravel Authentication and User Management.
Note: Laravel does not use Supabase Auth but rather implements its own authentication system!
<Admonition type="note">
Laravel implements its own authentication system rather than using Supabase Auth. Your users are stored in Laravel's `users` table, not in Supabase Auth.
</Admonition>
```bash
php artisan migrate
```
## 9. Start the app
## 8. Start the app
Run the development server. Go to http://127.0.0.1:8000 in a browser to see your application. You can also navigate to http://127.0.0.1:8000/register and http://127.0.0.1:8000/login to register and log in users.
@@ -101,6 +101,8 @@ Run the development server. Go to http://127.0.0.1:8000 in a browser to see your
php artisan serve
```
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Learn more about [Supabase Auth](/docs/guides/auth) if you want to replace Laravel's built-in authentication
@@ -13,20 +13,12 @@ breadcrumb: 'Framework Quickstarts'
Use the `create-next-app` command and the `with-supabase` template, to create a Next.js app pre-configured with [Cookie-based Auth](/docs/guides/auth/server-side/creating-a-client?queryGroups=package-manager&package-manager=npm&queryGroups=framework&framework=nextjs&queryGroups=environment&environment=server), [TypeScript](https://www.typescriptlang.org/), and [Tailwind CSS](https://tailwindcss.com/).
```bash
npx create-next-app -e with-supabase
npx create-next-app@latest my-app -e with-supabase
```
## 4. Install Supabase's Agent Skills (optional)
## 4. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
<$Partial path="quickstart_ai_tooling.mdx" />
## 5. Declare Supabase environment variables
@@ -45,7 +37,37 @@ NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=<SUBSTITUTE_SUPABASE_PUBLISHABLE_KEY>
<$Partial path="api_settings.mdx" variables={{ "framework": "nextjs", "tab": "frameworks" }} />
## 6. Query Supabase data from Next.js
## 6. Allow public access to the instruments page
The `with-supabase` template redirects unauthenticated visitors to the login page for most routes. The `instruments` table is publicly readable, so update `lib/supabase/proxy.ts` to skip that redirect for `/instruments`.
Find this `if` statement:
```ts name=lib/supabase/proxy.ts
if (
request.nextUrl.pathname !== "/" &&
!user &&
!request.nextUrl.pathname.startsWith("/login") &&
!request.nextUrl.pathname.startsWith("/auth")
) {
```
Add a condition for `/instruments`:
```ts name=lib/supabase/proxy.ts
if (
request.nextUrl.pathname !== "/" &&
!user &&
!request.nextUrl.pathname.startsWith("/login") &&
!request.nextUrl.pathname.startsWith("/auth") &&
request.nextUrl.pathname !== "/instruments" &&
!request.nextUrl.pathname.startsWith("/instruments/")
) {
```
## 7. Query Supabase data from Next.js
The `with-supabase` template already installs `@supabase/supabase-js` and `@supabase/ssr` and creates the clients for you, in `lib/supabase/client.ts` for the browser and `lib/supabase/server.ts` for Server Components. The code below imports the server client from there.
Create a new file at `app/instruments/page.tsx` and populate with the following.
@@ -59,7 +81,11 @@ import { Suspense } from "react";
async function InstrumentsData() {
const supabase = await createClient();
const { data: instruments } = await supabase.from("instruments").select();
const { data: instruments, error } = await supabase.from("instruments").select();
if (error) {
return <p>Error loading instruments: {error.message}</p>;
}
return <pre>{JSON.stringify(instruments, null, 2)}</pre>;
}
@@ -75,7 +101,7 @@ export default function Instruments() {
</$CodeTabs>
## 7. Start the app
## 8. Start the app
Run the development server, go to http://localhost:3000/instruments in a browser and you should see the list of instruments.
@@ -83,9 +109,11 @@ Run the development server, go to http://localhost:3000/instruments in a browser
npm run dev
```
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Explore [drop-in UI components](/ui) for your Supabase app
- Set up [Auth](/docs/guides/auth) for your app
- [Insert more data](/docs/guides/database/import-data) into your database
- Upload and serve static files using [Storage](/docs/guides/storage)
- Explore [drop-in UI components](/ui) for your Supabase app
@@ -16,18 +16,20 @@ Create a Nuxt app using the `npx nuxi` command.
npx nuxi@latest init my-app
```
## 4. Install Supabase's Agent Skills (optional)
<Admonition type="note">
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
The CLI prompts for a template, a package manager, and whether to initialize a git repository. Choose a minimal template, or pass flags to skip the prompts (required in non-interactive shells):
```bash
npx skills add supabase/agent-skills
npx nuxi@latest init my-app --template minimal --no-gitInit --packageManager npm
```
</Admonition>
## 4. Set up AI tooling (optional)
<$Partial path="quickstart_ai_tooling.mdx" />
## 5. Install the Supabase client library
The fastest way to get started is to use the `supabase-js` client library which provides a convenient interface for working with Supabase from a Nuxt app.
@@ -70,20 +72,37 @@ export default defineNuxtConfig({
<$Partial path="api_settings.mdx" variables={{ "framework": "nuxt", "tab": "frameworks" }} />
## 7. Query data from the app
## 7. Create the Supabase client
In `app.vue`, create a Supabase client using your config values and replace the existing content with the following code.
Create a composable at `app/composables/useSupabase.ts` that builds the client from your config values. `useRuntimeConfig()` is only available inside a Nuxt context, such as a composable or a component's `setup`, so the client is created there rather than at the top level of a module. Nuxt auto-imports anything in `app/composables/`, so you don't need to import `useSupabase` where you use it.
```vue name=app.vue
<script setup>
```ts name=app/composables/useSupabase.ts
import { createClient } from '@supabase/supabase-js'
const config = useRuntimeConfig()
const supabase = createClient(config.public.supabaseUrl, config.public.supabasePublishableKey)
export function useSupabase() {
const config = useRuntimeConfig()
return createClient(config.public.supabaseUrl, config.public.supabasePublishableKey)
}
```
## 8. Query data from the app
In `app/app.vue`, replace the existing content with the following code.
```vue name=app/app.vue
<script setup>
const supabase = useSupabase()
const instruments = ref([])
const error = ref(null)
async function getInstruments() {
const { data } = await supabase.from('instruments').select()
const { data, error: fetchError } = await supabase.from('instruments').select()
if (fetchError) {
error.value = fetchError
return
}
instruments.value = data
}
@@ -93,13 +112,20 @@ onMounted(() => {
</script>
<template>
<ul>
<p v-if="error">Error loading instruments: {{ error.message }}</p>
<ul v-else>
<li v-for="instrument in instruments" :key="instrument.id">{{ instrument.name }}</li>
</ul>
</template>
```
## 8. Start the app
<Admonition type="note">
This example fetches data in `onMounted`, so the instrument list appears after the page loads in the browser.
</Admonition>
## 9. Start the app
Start the app, navigate to http://localhost:3000 in the browser, and you should see the list of instruments.
@@ -113,9 +139,11 @@ The community-maintained [@nuxtjs/supabase](https://supabase.nuxtjs.org/) module
</Admonition>
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Explore [drop-in UI components](/ui) for your Supabase app
- Set up [Auth](/docs/guides/auth) for your app
- [Insert more data](/docs/guides/database/import-data) into your database
- Upload and serve static files using [Storage](/docs/guides/storage)
- Explore [drop-in UI components](/ui) for your Supabase app
@@ -16,17 +16,9 @@ Create a React app using a [Vite](https://vitejs.dev/guide/) template.
npm create vite@latest my-app -- --template react
```
## 4. Install Supabase's Agent Skills (optional)
## 4. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
<$Partial path="quickstart_ai_tooling.mdx" />
## 5. Install the Supabase client library
@@ -55,18 +47,27 @@ VITE_SUPABASE_PUBLISHABLE_KEY=<SUBSTITUTE_SUPABASE_PUBLISHABLE_KEY>
<$Partial path="api_settings.mdx" variables={{ "framework": "react", "tab": "frameworks" }} />
## 7. Query data from the app
## 7. Create the Supabase client
Replace the contents of `App.jsx` with a `getInstruments` function that fetches the data and displays the query result on the page using a Supabase client.
Create a `src/lib` directory in your React app, create a file called `supabaseClient.js`, and add the following code to initialize the Supabase client:
```js name=src/lib/supabaseClient.js
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
const supabasePublishableKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
export const supabase = createClient(supabaseUrl, supabasePublishableKey)
```
## 8. Query data from the app
Replace the contents of `App.jsx` with a `getInstruments` function that fetches the data and displays the query result on the page.
```js name=src/App.jsx
import { createClient } from '@supabase/supabase-js'
import { useEffect, useState } from 'react'
const supabase = createClient(
import.meta.env.VITE_SUPABASE_URL,
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
)
import { supabase } from './lib/supabaseClient'
function App() {
const [instruments, setInstruments] = useState([])
@@ -89,7 +90,7 @@ function App() {
return (
<ul>
{instruments.map((instrument) => (
<li key={instrument.name}>{instrument.name}</li>
<li key={instrument.id}>{instrument.name}</li>
))}
</ul>
)
@@ -98,7 +99,7 @@ function App() {
export default App
```
## 8. Start the app
## 9. Start the app
Run the development server, go to http://localhost:5173 in a browser, and you should see the list of instruments.
@@ -106,9 +107,11 @@ Run the development server, go to http://localhost:5173 in a browser, and you sh
npm run dev
```
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Explore [drop-in UI components](/ui) for your Supabase app
- Set up [Auth](/docs/guides/auth) for your app
- [Insert more data](/docs/guides/database/import-data) into your database
- Upload and serve static files using [Storage](/docs/guides/storage)
- Explore [drop-in UI components](/ui) for your Supabase app
@@ -10,6 +10,12 @@ breadcrumb: 'Framework Quickstarts'
Save your database password securely. You need it for the connection string.
<Admonition type="note">
This quickstart uses Prisma migrations against your Postgres database. Use a **dedicated Supabase project** (or an empty database) so Prisma does not try to reconcile tables created by other apps or quickstarts.
</Admonition>
## 2. Gather database connection strings
Open the project [**Connect** panel](/dashboard/project/_?showConnect=true&connectTab=direct). This quickstart connects using the [**Transaction pooler**](/dashboard/project/_?showConnect=true&connectTab=direct&method=transaction) and [**Session pooler**](/dashboard/project/_?showConnect=true&connectTab=direct&method=session) mode. Transaction mode is used for application queries and Session mode is used for running migrations with Prisma.
@@ -18,7 +24,7 @@ To do this, set the connection mode to `Transaction` in the [Database Settings p
To get the Session mode connection pooler string, change the port of the connection string from the dashboard to 5432.
You will need the Transaction mode connection string and the Session mode connection string to set up environment variables in Step 6.
You will need the Transaction mode connection string and the Session mode connection string to set up environment variables in Step 5.
<Admonition type="note">
@@ -34,31 +40,21 @@ Create a RedwoodJS app with TypeScript.
The [`yarn` package manager](https://yarnpkg.com) is required to create a RedwoodJS app. You will use it to run RedwoodJS commands later.
While TypeScript is recommended, If you want a JavaScript app, omit the `--ts` flag.
While TypeScript is recommended, if you want a JavaScript app, omit the `--ts` flag.
RedwoodJS 8.x officially supports Node `20.x`. On Node 22 or later, `create-redwood-app` may prompt you to override the version check. Select **Override error and continue install**, or switch to Node 20 with a version manager such as [`nvm`](https://github.com/nvm-sh/nvm).
</Admonition>
```bash
yarn create redwood-app my-app --ts
yarn create redwood-app my-app --ts --git-init false
```
## 4. Install Supabase's Agent Skills (optional)
## 4. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
<$Partial path="quickstart_ai_tooling.mdx" />
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
## 5. Install MCP server (optional)
The Supabase MCP server connects AI assistants to Supabase, allowing you to interact with your projects on your behalf. Find out more on how to add it to your client in [the MCP docs](/docs/guides/ai-tools/mcp).
## 6. Configure environment variables
## 5. Configure environment variables
In your `.env` file, add the following environment variables for your database connection:
@@ -67,18 +63,18 @@ In your `.env` file, add the following environment variables for your database c
- The `DIRECT_URL` should use the Session mode connection string you copied in Step 2.
```bash name=.env
# Transaction mode connection string — used by Prisma Client for app queries
DATABASE_URL="postgres://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@aws-[REGION].pooler.supabase.com:6543/postgres?pgbouncer=true&connection_limit=1"
# Transaction mode connection string for Prisma Client app queries
DATABASE_URL="postgres://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@[POOLER-HOST]:6543/postgres?pgbouncer=true&connection_limit=1"
# Session mode connection string — used by Prisma Migrate
DIRECT_URL="postgres://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@aws-[REGION].pooler.supabase.com:5432/postgres"
# Session mode connection string for Prisma Migrate
DIRECT_URL="postgres://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@[POOLER-HOST]:5432/postgres"
```
## 7. Update your Prisma schema
## 6. Update your Prisma schema
By default, RedwoodJS ships with a SQLite database, but we want to use Postgres.
Update your Prisma schema file `api/db/schema.prisma` to use your Supabase Postgres database connection environment variables you set up in Step 6.
Update your Prisma schema file `api/db/schema.prisma` to use your Supabase Postgres database connection environment variables you set up in Step 5.
```prisma name=api/db/schema.prisma
datasource db {
@@ -88,10 +84,16 @@ datasource db {
}
```
## 8. Create the instrument model and apply a schema migration
## 7. Create the instrument model and apply a schema migration
Create the Instrument model in `api/db/schema.prisma` and then run `yarn rw prisma migrate dev` from your terminal to apply the migration.
<Admonition type="note">
`yarn rw prisma migrate dev` requires an interactive terminal. It prompts for a migration name and cannot run in fully non-interactive CI shells.
</Admonition>
```prisma name=api/db/schema.prisma
model Instrument {
id Int @id @default(autoincrement())
@@ -99,7 +101,7 @@ model Instrument {
}
```
## 9. Update seed script
## 8. Update seed script
Seed the database with a few instruments.
@@ -128,7 +130,7 @@ export default async () => {
}
```
## 10. Seed your database
## 9. Seed your database
Run the seed database command to populate the `Instrument` table with the instruments you created.
@@ -142,7 +144,7 @@ The reset database command `yarn rw prisma db reset` recreates the tables and al
yarn rw prisma db seed
```
## 11. Scaffold the instrument UI
## 10. Scaffold the instrument UI
Use RedwoodJS generators to scaffold a CRUD UI for the `Instrument` model.
@@ -150,16 +152,18 @@ Use RedwoodJS generators to scaffold a CRUD UI for the `Instrument` model.
yarn rw g scaffold instrument
```
## 12. Start the app
## 11. Start the app
Start the app via `yarn rw dev`. A browser will open to the RedwoodJS Splash page.
## 13. View instruments UI
## 12. View instruments UI
Click on `/instruments` to visit http://localhost:8910/instruments where should see the list of instruments.
You may now edit, delete, and add new instruments using the scaffolded UI.
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Set up [Auth](/docs/guides/auth) for your app
@@ -18,18 +18,22 @@ The `refine-supabase` preset adds `@refinedev/supabase` supplementary package th
npm create refine-app@latest -- --preset refine-supabase my-app
```
## 4. Install Supabase's Agent Skills (optional)
<Admonition type="note">
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
The CLI may prompt for an email address. The `refine-supabase` preset also ships with demo Supabase credentials. Replace them in step 5 with your own project.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
To skip the email prompt in a non-interactive shell, pipe a blank line:
```bash
npx skills add supabase/agent-skills
printf '\n' | npm create refine-app@latest -- --preset refine-supabase my-app
```
</Admonition>
## 4. Set up AI tooling (optional)
<$Partial path="quickstart_ai_tooling.mdx" />
## 5. Update `supabaseClient` with environment variables
Create a `.env` file and populate it with your Supabase URL and publishable key, which you can get from the helper below, or [from the project **Connect** panel](/dashboard/project/_?showConnect=true&framework=refine&connectTab=frameworks).
@@ -45,24 +49,15 @@ VITE_SUPABASE_URL=<SUBSTITUTE_SUPABASE_URL>
VITE_SUPABASE_PUBLISHABLE_KEY=<SUBSTITUTE_SUPABASE_PUBLISHABLE_KEY>
```
Update `src/utility/supabaseClient.ts` to read the URL and publishable key from these environment variables. The `supabaseClient` is used in auth provider and data provider methods that allow the Refine app to connect to your Supabase backend.
The `refine-supabase` preset hardcodes Refine's own demo Supabase project in `src/providers/constants.ts`, and initializes the client from it in `src/providers/supabase-client.ts`. Replace the hardcoded values so the client reads your project credentials from the environment variables above instead:
```ts name=src/utility/supabaseClient.ts
import { createClient } from '@refinedev/supabase'
const SUPABASE_URL = import.meta.env.VITE_SUPABASE_URL
const SUPABASE_KEY = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
export const supabaseClient = createClient(SUPABASE_URL, SUPABASE_KEY, {
db: {
schema: 'public',
},
auth: {
persistSession: true,
},
})
```ts name=src/providers/constants.ts
export const SUPABASE_URL = import.meta.env.VITE_SUPABASE_URL
export const SUPABASE_KEY = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
```
The `supabaseClient` is used by the auth and data providers to connect your Refine app to Supabase.
<$Partial path="api_settings.mdx" variables={{ "framework": "refine", "tab": "frameworks" }} />
## 6. Add instruments resource and pages
@@ -71,7 +66,11 @@ Use the following code to automatically add resources and generate code for the
This defines pages for `list`, `create`, `show` and `edit` actions inside the `src/pages/instruments/` directory with a `<HeadlessInferencer />` component.
The `<HeadlessInferencer />` component depends on `@refinedev/react-table` and `@refinedev/react-hook-form` packages. To avoid errors, you should install them as dependencies with `npm install @refinedev/react-table @refinedev/react-hook-form`.
The `<HeadlessInferencer />` component depends on `@refinedev/react-table`, `@refinedev/react-hook-form`, and `react-live` packages. To avoid errors, install them as dependencies:
```bash
npm install @refinedev/react-table @refinedev/react-hook-form react-live
```
<Admonition type="note">
@@ -103,26 +102,27 @@ import routerProvider, {
NavigateToResource,
UnsavedChangesNotifier,
} from '@refinedev/react-router'
import { dataProvider, liveProvider } from '@refinedev/supabase'
import { BrowserRouter, Route, Routes } from 'react-router-dom'
import { liveProvider } from '@refinedev/supabase'
import { BrowserRouter, Route, Routes } from 'react-router'
import './App.css'
import authProvider from './authProvider'
import authProvider from './providers/auth'
import { dataProvider } from './providers/data'
import { supabaseClient } from './providers/supabase-client'
import {
InstrumentsCreate,
InstrumentsEdit,
InstrumentsList,
InstrumentsShow,
} from './pages/instruments'
import { supabaseClient } from './utility'
function App() {
return (
<BrowserRouter>
<RefineKbarProvider>
<Refine
dataProvider={dataProvider(supabaseClient)}
dataProvider={dataProvider}
liveProvider={liveProvider(supabaseClient)}
authProvider={authProvider}
routerProvider={routerProvider}
@@ -161,9 +161,41 @@ function App() {
export default App
```
## 8. Start the app
## 8. Allow writes to the instruments table
Run the development server, go to http://localhost:5173/instruments in a browser, and you should see the instruments pages along the `/instruments` routes. You can edit and add new instruments using the Inferencer-generated UI.
The scaffolded pages create and edit instruments, but the database setup in step 2 grants read access only. Without write privileges and matching policies, the create and edit pages fail with `permission denied for table instruments`.
Run the following in the [SQL Editor](/dashboard/project/_/sql/new) to grant the privileges and add the policies:
```sql SQL_EDITOR
grant insert, update, delete on public.instruments to anon;
create policy "public can insert instruments"
on public.instruments
for insert to anon
with check (true);
create policy "public can update instruments"
on public.instruments
for update to anon
using (true)
with check (true);
create policy "public can delete instruments"
on public.instruments
for delete to anon
using (true);
```
<Admonition type="caution">
These policies let anyone with your publishable key modify the `instruments` table. They exist so you can try the scaffolded UI against sample data. Scope writes to authenticated users before you put real data in this table.
</Admonition>
## 9. Start the app
Run the development server, then open `/instruments` in your browser (Vite defaults to http://localhost:5173). You should see the instruments pages along the `/instruments` routes. You can edit and add new instruments using the Inferencer-generated UI.
```bash
npm run dev
@@ -171,6 +203,8 @@ npm run dev
The Inferencer auto-generated code gives you a good starting point on which to keep building your `list`, `create`, `show` and `edit` pages. You can get these by clicking the `Show the auto-generated code` buttons in their respective pages.
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Set up [Auth](/docs/guides/auth) for your app
@@ -10,6 +10,12 @@ breadcrumb: 'Framework Quickstarts'
Save your database password securely. You need it for the connection string.
<Admonition type="note">
This guide uses Rails' own Active Record models and migrations, not the shared `instruments` sample table used by other quickstarts.
</Admonition>
## 2. Create a Rails project
With your Ruby and Rails versions up to date, run `rails new` on your terminal to scaffold a new project.
@@ -23,41 +29,21 @@ rails new blog -d=postgresql
cd blog
```
## 3. Install Supabase's Agent Skills (optional)
## 3. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
<$Partial path="quickstart_ai_tooling.mdx" />
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
## 4. Set up the Postgres connection details
To install, run the following command in the root of your project:
<$Partial path="quickstart_connection_string.mdx" />
Set the connection string as an environment variable. Rails reads `DATABASE_URL` from the environment and connects with it, so you don't need to edit `config/database.yml`. The export applies to the current shell session, so run it in the same shell as the Rails commands in the following steps.
```bash
npx skills add supabase/agent-skills
export DATABASE_URL=postgres://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@[POOLER-HOST]:5432/postgres?sslmode=require
```
## 4. Install MCP server (optional)
The Supabase MCP server connects AI assistants to Supabase, allowing you to interact with your projects on your behalf. Find out more on how to add it to your client in [the MCP docs](/docs/guides/ai-tools/mcp).
## 5. Set up the Postgres connection details
Navigate to your project dashboard and click on [Connect](/dashboard/project/_?showConnect=true&connectTab=direct&method=session).
Look for the Session Pooler connection string and copy the string. You will need to replace the Password with your saved database password, and [percent-encode](https://en.wikipedia.org/wiki/Percent-encoding) any reserved characters it contains, such as `&`, `#`, `?`, or a space. You can reset your database password in your [Database Settings](/dashboard/project/_/database/settings) if you do not have it.
<Admonition type="note">
If you're in an [IPv6 environment](https://github.com/orgs/supabase/discussions/27034) or have the IPv4 Add-On, you can use the direct connection string instead of Supavisor in Session mode.
</Admonition>
Set the connection string as an environment variable. Rails reads `DATABASE_URL` from the environment and connects with it, so you don't need to edit `config/database.yml`. The export applies to the current shell session, so run it in the same shell as the Rails commands in the following steps. `sslmode=require` stops the driver from falling back to sending your data in plaintext.
```bash
export DATABASE_URL=postgres://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@aws-[REGION].pooler.supabase.com:5432/postgres?sslmode=require
```
## 6. Create and run a database migration
## 5. Create and run a database migration
Rails includes Active Record as the ORM as well as database migration tooling which generates the SQL migration files for you.
@@ -68,7 +54,7 @@ bin/rails generate model Article title:string body:text
bin/rails db:migrate
```
## 7. Use the model to interact with the database
## 6. Use the model to interact with the database
You can use the included Rails console to interact with the database. For example, you can create new entries or list all entries in a Model's table.
@@ -83,7 +69,7 @@ article.save # Saves the entry to the database
Article.all
```
## 8. Start the app
## 7. Start the app
Run the development server. Go to http://127.0.0.1:3000 in a browser to see your application running.
@@ -91,6 +77,8 @@ Run the development server. Go to http://127.0.0.1:3000 in a browser to see your
bin/rails server
```
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Set up [Auth](/docs/guides/auth) for your app
@@ -13,21 +13,19 @@ breadcrumb: 'Framework Quickstarts'
Create a SolidJS app using the `degit` command.
```bash
npx degit solidjs/templates/js my-app
npx degit solidjs/templates/vanilla/basic my-app
```
## 4. Install Supabase's Agent Skills (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
The template ships with a `pnpm-lock.yaml`. Remove it so `npm install` in the next steps doesn't create a second, conflicting lockfile:
```bash
npx skills add supabase/agent-skills
rm my-app/pnpm-lock.yaml
```
## 4. Set up AI tooling (optional)
<$Partial path="quickstart_ai_tooling.mdx" />
## 5. Install the Supabase client library
The fastest way to get started is to use the `supabase-js` client library which provides a convenient interface for working with Supabase from a SolidJS app.
@@ -55,23 +53,35 @@ VITE_SUPABASE_PUBLISHABLE_KEY=<SUBSTITUTE_SUPABASE_PUBLISHABLE_KEY>
<$Partial path="api_settings.mdx" variables={{ "framework": "solidjs", "tab": "frameworks" }} />
## 7. Query data from the app
## 7. Create the Supabase client
In `App.jsx`, create a Supabase client to fetch the instruments data.
Create a `src/lib` directory in your SolidJS app, create a file called `supabaseClient.ts`, and add the following code to initialize the Supabase client:
Add a `getInstruments` function to fetch the data and display the query result to the page.
```jsx name=src/App.jsx
```ts name=src/lib/supabaseClient.ts
import { createClient } from '@supabase/supabase-js'
import { createResource, For } from 'solid-js'
const supabase = createClient(
import.meta.env.VITE_SUPABASE_URL,
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
)
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
const supabasePublishableKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
export const supabase = createClient(supabaseUrl, supabasePublishableKey)
```
## 8. Query data from the app
In `src/App.tsx`, add a `getInstruments` function to fetch the data and display the query result to the page.
```tsx name=src/App.tsx
import { createResource, For, Show } from 'solid-js'
import { supabase } from './lib/supabaseClient'
async function getInstruments() {
const { data } = await supabase.from('instruments').select()
const { data, error } = await supabase.from('instruments').select()
if (error) {
throw error
}
return data
}
@@ -79,16 +89,21 @@ function App() {
const [instruments] = createResource(getInstruments)
return (
<ul>
<For each={instruments()}>{(instrument) => <li>{instrument.name}</li>}</For>
</ul>
<Show
when={!instruments.error}
fallback={<p>Error loading instruments: {instruments.error?.message}</p>}
>
<ul>
<For each={instruments()}>{(instrument) => <li>{instrument.name}</li>}</For>
</ul>
</Show>
)
}
export default App
```
## 8. Start the app
## 9. Start the app
Start the app and go to http://localhost:3000 in a browser and you should see the list of instruments.
@@ -96,6 +111,8 @@ Start the app and go to http://localhost:3000 in a browser and you should see th
npm run dev
```
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Set up [Auth](/docs/guides/auth) for your app
@@ -17,6 +17,12 @@ Before you begin, make sure you have:
Save your database password securely. You need it for the connection string.
<Admonition type="note">
This guide uses Spring Boot's own JPA entities and generated schema, not the shared `instruments` sample table used by other quickstarts.
</Admonition>
## 2. Create a Spring Boot project
Use [Spring Initializr](https://start.spring.io) to scaffold a new project with the Web, Spring Data JPA, and Postgres Driver dependencies. Run the following from the directory where you keep your projects.
@@ -33,44 +39,22 @@ curl https://start.spring.io/starter.zip \
unzip instruments.zip -d instruments && cd instruments
```
## 3. Install Supabase's Agent Skills (optional)
## 3. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
<$Partial path="quickstart_ai_tooling.mdx" />
## 4. Set up the Postgres connection details
Navigate to your project dashboard and click on [Connect](/dashboard/project/_?showConnect=true&connectTab=direct&method=session).
<$Partial path="quickstart_connection_string.mdx" />
<Admonition type="caution">
The Transaction pooler (port `6543`) doesn't work as your app's main data source, because Spring Data JPA uses Hibernate, which relies on server-side prepared statements. Use the Session pooler, or the direct connection string if you're in an [IPv6 environment](/docs/guides/troubleshooting/supabase--your-network-ipv4-and-ipv6-compatibility-cHe3BP) or have the [IPv4 Add-On](/docs/guides/platform/ipv4-address).
</Admonition>
Under the **Session pooler** (port `5432`), select the **JDBC** tab and copy the connection string. Replace the password placeholder with your saved database password, and [percent-encode](https://en.wikipedia.org/wiki/Percent-encoding) any reserved characters it contains, such as `&`, `#`, `?`, or a space.
<Admonition type="note">
You can reset your database password in your [Database Settings](/dashboard/project/_/database/settings) if you do not have it.
</Admonition>
Select the **JDBC** tab to copy the connection string in the right format for Spring Boot.
The connection string contains your database password, and `application.properties` is committed with your project. Set the string as an environment variable instead, and set it the same way on whatever platform you deploy to.
```bash
export SUPABASE_DB_URL='jdbc:postgresql://aws-[REGION].pooler.supabase.com:5432/postgres?user=postgres.[PROJECT-REF]&password=[YOUR-PASSWORD]&sslmode=require'
export SUPABASE_DB_URL='jdbc:postgresql://[POOLER-HOST]:5432/postgres?user=postgres.[PROJECT-REF]&password=[YOUR-PASSWORD]&sslmode=require'
```
The string you copied doesn't set `sslmode`, so add it. The driver defaults to `prefer`, which falls back to sending your data in plaintext if the encrypted attempt fails. You can also [enforce SSL](/docs/guides/platform/ssl-enforcement) on the database side.
Then reference the variable, along with the driver, in `src/main/resources/application.properties`.
```text name=src/main/resources/application.properties
@@ -85,7 +69,13 @@ If the app fails to start with `Unable to determine Dialect without JDBC metadat
By default Hibernate creates tables in the `public` schema. We recommend changing this as Supabase exposes the `public` schema as a [data API](/docs/guides/api).
Create the schema from the [Table Editor](/dashboard/project/_/editor) as your app will need it before start. Then point **Hibernate** at it in `application.properties`.
Create the `app` schema before you start the app. Hibernate creates tables in that schema on startup, but it does not create the schema itself. Run the following in the [SQL Editor](/dashboard/project/_/sql/new):
```sql SQL_EDITOR
create schema if not exists app;
```
Then point Hibernate at the schema in `application.properties`.
```text name=src/main/resources/application.properties
spring.jpa.properties.hibernate.default_schema=app
@@ -212,9 +202,11 @@ Run the Spring Boot app, and go to http://localhost:8080/instruments in your bro
./mvnw spring-boot:run
```
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Set up [Auth](/docs/guides/auth) for your app
- Replace `ddl-auto` with [database migrations](/docs/guides/deployment/database-migrations) before going to production
- [Insert more data](/docs/guides/database/import-data) into your database
- Upload and serve static files using [Storage](/docs/guides/storage)
- Replace `ddl-auto` with [database migrations](/docs/guides/deployment/database-migrations) before going to production
@@ -10,23 +10,15 @@ breadcrumb: 'Framework Quickstarts'
## 3. Create a SvelteKit app
Create a SvelteKit app using the `npm create` command.
Create a SvelteKit app using the `sv` CLI.
```bash
npx sv create my-app
```
## 4. Install Supabase's Agent Skills (optional)
## 4. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
<$Partial path="quickstart_ai_tooling.mdx" />
## 5. Install the Supabase client library
@@ -89,9 +81,16 @@ Create `+page.server.js` file in the `src/routes` directory with the following c
import { supabase } from '$lib/supabaseClient'
export async function load() {
const { data } = await supabase.from('instruments').select()
const { data, error } = await supabase.from('instruments').select()
if (error) {
console.error('Error loading instruments:', error.message)
return { instruments: [], error: error.message }
}
return {
instruments: data ?? [],
error: null,
}
}
```
@@ -107,15 +106,16 @@ type Instrument = {
}
export const load: PageServerLoad = async () => {
const { data, error } = await supabase.from('instruments').select<'instruments', Instrument>()
const { data, error } = await supabase.from('instruments').select<'*', Instrument>()
if (error) {
console.error('Error loading instruments:', error.message)
return { instruments: [] }
return { instruments: [], error: error.message }
}
return {
instruments: data ?? [],
error: null,
}
}
```
@@ -129,11 +129,15 @@ Replace the existing content in your `+page.svelte` file in the `src/routes` dir
let { data } = $props();
</script>
<ul>
{#each data.instruments as instrument}
<li>{instrument.name}</li>
{/each}
</ul>
{#if data.error}
<p>Error loading instruments: {data.error}</p>
{:else}
<ul>
{#each data.instruments as instrument}
<li>{instrument.name}</li>
{/each}
</ul>
{/if}
```
## 9. Start the app
@@ -144,6 +148,8 @@ Start the app and go to http://localhost:5173 in a browser and you should see th
npm run dev
```
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Set up [Auth](/docs/guides/auth) for your app
@@ -16,17 +16,9 @@ Create a TanStack Start app using the official CLI.
npx @tanstack/cli@latest create my-app
```
## 4. Install Supabase's Agent Skills (optional)
## 4. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
<$Partial path="quickstart_ai_tooling.mdx" />
## 5. Install the Supabase client libraries
@@ -57,8 +49,10 @@ VITE_SUPABASE_PUBLISHABLE_KEY=<SUBSTITUTE_SUPABASE_PUBLISHABLE_KEY>
TanStack Start needs two Supabase clients: a browser client for components that run in the browser, and a server client for loaders and server functions. Create a `src/lib/supabase` folder with a file for each client.
Both clients read the same two variables, through the API available in each environment. The browser client uses `import.meta.env`, which Vite replaces at build time. The server client uses `process.env`, which the server runtime populates from your `.env.local` file.
```ts name=src/lib/supabase/client.ts
/// <reference types="vite/types/importMeta.d.ts" />
/// <reference types="vite/client" />
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
@@ -99,29 +93,49 @@ export function createClient() {
## 8. Query Supabase data from TanStack Start
Replace the contents of `src/routes/index.tsx` with the following to add a loader that queries the `instruments` table through the server client. The loader runs on the server, so the data is part of the initial server-rendered response.
Create a server function that queries the `instruments` table through the server client. TanStack Start's import protection blocks direct server imports in route files, so wrap the Supabase call in `createServerFn`.
```ts name=src/lib/supabase/fetch-instruments-server-fn.ts
import { createServerFn } from '@tanstack/react-start'
import { createClient } from '@/lib/supabase/server'
export const fetchInstruments = createServerFn({ method: 'GET' }).handler(async () => {
const supabase = createClient()
const { data: instruments, error } = await supabase.from('instruments').select()
if (error) {
console.error(error)
return { instruments: [], error: error.message }
}
return { instruments, error: null }
})
```
Replace the contents of `src/routes/index.tsx` with the following to call the server function from a route loader. The loader runs on the server, so the data is part of the initial server-rendered response.
```tsx name=src/routes/index.tsx
import { createFileRoute } from '@tanstack/react-router'
import { createClient } from '@/lib/supabase/server'
import { fetchInstruments } from '@/lib/supabase/fetch-instruments-server-fn'
export const Route = createFileRoute('/')({
loader: async () => {
const supabase = createClient()
const { data: instruments } = await supabase.from('instruments').select()
return { instruments }
},
loader: async () => fetchInstruments(),
component: Home,
})
function Home() {
const { instruments } = Route.useLoaderData()
const { instruments, error } = Route.useLoaderData()
if (error) {
return <p>Error loading instruments: {error}</p>
}
return (
<ul>
{instruments?.map((instrument) => (
<li key={instrument.name}>{instrument.name}</li>
<li key={instrument.id}>{instrument.name}</li>
))}
</ul>
)
@@ -136,10 +150,11 @@ Run the development server, go to http://localhost:3000 in a browser and you sho
npm run dev
```
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Learn how to [protect routes and check sessions](/docs/guides/auth/server-side/creating-a-client?queryGroups=framework&framework=tanstack) with the server client
- Set up a complete [login and sign-up flow](/library/docs/tanstack/password-based-auth) from Supabase Library
- Explore [drop-in UI components](/ui) for your Supabase app
- Learn how to [protect routes and check sessions](/docs/guides/auth/server-side/creating-a-client?queryGroups=framework&framework=tanstack) with the server client, or drop in a complete [login and sign-up flow](/library/docs/tanstack/password-based-auth) from Supabase Library
- [Insert more data](/docs/guides/database/import-data) into your database
- Upload and serve static files using [Storage](/docs/guides/storage)
- Explore [drop-in UI components](/ui) for your Supabase app
@@ -16,17 +16,9 @@ Create a Vue app using the `npm init` command.
npm init vue@latest my-app
```
## 4. Install Supabase's Agent Skills (optional)
## 4. Set up AI tooling (optional)
Supabase's [Agent Skills](/docs/guides/ai-tools/ai-skills) is a curated set of instructions that give your AI agent procedural knowledge about working with Supabase.
Install them so your AI coding agent can produce more accurate, reliable code using current Supabase patterns, such as authentication, server-side rendering, and database migrations, rather than relying solely on training data.
To install, run the following command in the root of your project:
```bash
npx skills add supabase/agent-skills
```
<$Partial path="quickstart_ai_tooling.mdx" />
## 5. Install the Supabase client library
@@ -57,9 +49,15 @@ VITE_SUPABASE_PUBLISHABLE_KEY=<SUBSTITUTE_SUPABASE_PUBLISHABLE_KEY>
## 7. Create the Supabase client
Create a `/src/lib` directory in your Vue app, create a file called `supabaseClient.js` and add the following code to initialize the Supabase client:
Create a `/src/lib` directory in your Vue app, create a file called `supabaseClient.ts` and add the following code to initialize the Supabase client:
```js name=src/lib/supabaseClient.js
<Admonition type="note">
`npm init vue@latest` scaffolds a TypeScript project by default. If you chose a JavaScript-only project, use a `.js` extension instead and drop the type import.
</Admonition>
```ts name=src/lib/supabaseClient.ts
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
@@ -73,15 +71,27 @@ export const supabase = createClient(supabaseUrl, supabasePublishableKey)
Replace the existing content in your `App.vue` file with the following code.
```vue name=src/App.vue
<script setup>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { supabase } from './lib/supabaseClient'
const instruments = ref([])
type Instrument = {
id: number
name: string
}
const instruments = ref<Instrument[]>([])
const error = ref<string | null>(null)
async function getInstruments() {
const { data } = await supabase.from('instruments').select()
const { data, error: fetchError } = await supabase.from('instruments').select()
if (fetchError) {
error.value = fetchError.message
return
}
instruments.value = data
}
@@ -91,7 +101,8 @@ onMounted(() => {
</script>
<template>
<ul>
<p v-if="error">Error loading instruments: {{ error }}</p>
<ul v-else>
<li v-for="instrument in instruments" :key="instrument.id">{{ instrument.name }}</li>
</ul>
</template>
@@ -105,9 +116,11 @@ Start the app and go to http://localhost:5173 in a browser and you should see th
npm run dev
```
<$Partial path="quickstart_going_to_production.mdx" />
## Next steps
- Explore [drop-in UI components](/ui) for your Supabase app
- Set up [Auth](/docs/guides/auth) for your app
- [Insert more data](/docs/guides/database/import-data) into your database
- Upload and serve static files using [Storage](/docs/guides/storage)
- Explore [drop-in UI components](/ui) for your Supabase app
@@ -65,7 +65,7 @@ export const gettingStartedFrameworkQuickstarts: ContentListingGroup = {
icon: '/docs/img/icons/react-icon',
hasLightIcon: false,
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a React app.',
'Build single-page apps from reusable components, and query Supabase Postgres from the browser.',
},
{
title: 'Next.js',
@@ -73,7 +73,7 @@ export const gettingStartedFrameworkQuickstarts: ContentListingGroup = {
icon: '/docs/img/icons/nextjs-icon',
hasLightIcon: true,
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Next.js app.',
'Full-stack React with server rendering, wired to Supabase Postgres and cookie-based auth.',
},
{
title: 'Nuxt',
@@ -81,7 +81,15 @@ export const gettingStartedFrameworkQuickstarts: ContentListingGroup = {
icon: '/docs/img/icons/nuxt-icon',
hasLightIcon: false,
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Nuxt app.',
'Full-stack Vue with server rendering, reading Postgres through a Supabase composable.',
},
{
title: 'Astro',
href: '/guides/getting-started/quickstarts/astrojs',
icon: '/docs/img/icons/astro-icon',
hasLightIcon: true,
description:
'Content-driven sites that render on the server and pull Supabase Postgres data per request.',
},
{
title: 'Hono',
@@ -89,7 +97,7 @@ export const gettingStartedFrameworkQuickstarts: ContentListingGroup = {
icon: '/docs/img/icons/hono-icon',
hasLightIcon: false,
description:
'Learn how to create a Supabase project, add some sample data to your database, secure it with auth, and query the data from a Hono app.',
'Lightweight web APIs with Supabase Auth anonymous sign-in and RLS-protected reads.',
},
{
title: 'RedwoodJS',
@@ -97,7 +105,15 @@ export const gettingStartedFrameworkQuickstarts: ContentListingGroup = {
icon: '/docs/img/icons/redwood-icon',
hasLightIcon: false,
description:
'Learn how to create a Supabase project, add some sample data to your database using Prisma migration and seeds, and query the data from a RedwoodJS app.',
'Full-stack React and GraphQL, with Prisma migrations against your Supabase Postgres database.',
},
{
title: 'Expo React Native',
href: '/guides/getting-started/quickstarts/expo-react-native',
icon: '/docs/img/icons/expo-icon',
hasLightIcon: true,
description:
'Ship iOS and Android from one React Native codebase, backed by Supabase Postgres.',
},
{
title: 'Flutter',
@@ -105,8 +121,7 @@ export const gettingStartedFrameworkQuickstarts: ContentListingGroup = {
icon: '/docs/img/icons/flutter-icon',
hasLightIcon: false,
feature: 'sdk:dart',
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Flutter app.',
description: 'Ship iOS and Android from one Dart codebase, backed by Supabase Postgres.',
},
{
title: 'iOS SwiftUI',
@@ -114,8 +129,7 @@ export const gettingStartedFrameworkQuickstarts: ContentListingGroup = {
icon: '/docs/img/icons/swift-icon',
hasLightIcon: false,
feature: 'sdk:swift',
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from an iOS app.',
description: 'Native iOS apps in Swift, reading Postgres through the Supabase Swift SDK.',
},
{
title: 'Android Kotlin',
@@ -124,15 +138,14 @@ export const gettingStartedFrameworkQuickstarts: ContentListingGroup = {
hasLightIcon: false,
feature: 'sdk:kotlin',
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from an Android Kotlin app.',
'Native Android apps in Kotlin and Jetpack Compose, using the Supabase Kotlin SDK.',
},
{
title: 'SvelteKit',
href: '/guides/getting-started/quickstarts/sveltekit',
icon: '/docs/img/icons/svelte-icon',
hasLightIcon: false,
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a SvelteKit app.',
description: 'Full-stack Svelte that loads Supabase Postgres data in server load functions.',
},
{
title: 'SolidJS',
@@ -140,7 +153,7 @@ export const gettingStartedFrameworkQuickstarts: ContentListingGroup = {
icon: '/docs/img/icons/solidjs-icon',
hasLightIcon: false,
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a SolidJS app.',
'Fine-grained reactive UIs that load Supabase Postgres data with Solid resources.',
},
{
title: 'Vue',
@@ -148,15 +161,14 @@ export const gettingStartedFrameworkQuickstarts: ContentListingGroup = {
icon: '/docs/img/icons/vuejs-icon',
hasLightIcon: false,
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Vue app.',
'Build single-page apps with the Vue composition API, backed by Supabase Postgres.',
},
{
title: 'TanStack Start',
href: '/guides/getting-started/quickstarts/tanstack',
icon: '/docs/img/icons/tanstack-icon',
hasLightIcon: true,
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a TanStack Start app.',
description: 'Type-safe full-stack React that queries Supabase Postgres in server functions.',
},
{
title: 'Refine',
@@ -164,7 +176,30 @@ export const gettingStartedFrameworkQuickstarts: ContentListingGroup = {
icon: '/docs/img/icons/refine-icon',
hasLightIcon: false,
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Refine app.',
'Scaffold CRUD dashboards and admin panels straight from your Supabase Postgres tables.',
},
{
title: 'Python',
href: '/guides/getting-started/quickstarts/flask',
icon: '/docs/img/icons/python-icon',
hasLightIcon: false,
description: 'Serve Flask web apps that query Postgres with the Supabase Python client.',
},
{
title: 'Laravel',
href: '/guides/getting-started/quickstarts/laravel',
icon: '/docs/img/icons/laravel-icon',
hasLightIcon: false,
description:
'Full-stack PHP with Eloquent ORM connected directly to your Supabase Postgres database.',
},
{
title: 'Ruby on Rails',
href: '/guides/getting-started/quickstarts/ruby-on-rails',
icon: '/docs/img/icons/rails-icon',
hasLightIcon: false,
description:
'Convention-driven Ruby apps with Active Record connected directly to your Supabase Postgres database.',
},
],
}
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1888" height="1888" fill="#ff2d20"><path d="M791.5 1714L215 1381.5c-8.5-5.5-15-8.5-15-19.5V357.5c0-8.158 5-13.5 9.5-16L502 173c9.5-5.5 17.5-5.5 26.5 0L819 340c11.5 6.5 12 15 12 22.5v622L1073.5 845V527c0-11 5-17.5 17-24.5L1380 336c7-4 12.5-4 19.5 0l295 170c9.5 5.5 10.5 12 10.5 21.5V858c0 10.5-2.5 16-13 22.5l-278.5 160v317c0 12.5-3 17.5-14 24L821 1714c-11 6-18.5 6-29.5 0zm-9-61.5v-279l-276-156c-9-5.5-15.5-9.5-15.5-23V543L248 403.5V1345zm583-307.5v-277L831 1373.5v279zm-25.528-318.167L1098 886.5 565 1194l241 137zM782.5 1012V403L540 543v609zm583-28V708l-243-140v277zm291-139V568l-243 140v276zm-267-179.5l242-139.5-242-139.5L1147 526zM757.635 361.004L515 221.5 273 361l242 140z"/></svg>

After

Width:  |  Height:  |  Size: 733 B

@@ -0,0 +1 @@
<svg height="90" viewBox="0 0 90 90" width="90" fill="#D30001" xmlns="http://www.w3.org/2000/svg"><path d="m418.082357 25.9995403v4.1135034h-7.300339v1.89854h3.684072c1.972509 0 4.072534 1.4664311 4.197997 3.9665124l.005913.2373977v1.5821167c-.087824 3.007959-2.543121 4.1390018-4.071539 4.2011773l-.132371.0027328h-7.390745v-4.0909018l7.481152-.0226016v-1.9889467l-1.190107.0007441-.346911.0008254-.084566.0003251-.127643.0007097-.044785.0003793-.055764.0007949-.016378.0008259c.000518.0004173.013246.0008384.034343.0012518l.052212.000813c.030547.0003979.066903.0007803.105225.0011355l.078131.0006709-.155385-.0004701c-.31438-.001557-.85249-.0041098-1.729029-.0080055-1.775258 0-4.081832-1.3389153-4.219994-3.9549201l-.006518-.24899v-1.423905c0-2.6982402 2.278213-4.182853 4.065464-4.2678491l.161048-.003866zm-18.691579 0v11.8658752h6.170255v4.1361051h-10.735792v-16.0019803zm-6.441475 0v16.0019803h-4.588139v-16.0019803zm-10.803597 0c1.057758 0 4.04923.7305141 4.198142 3.951222l.005768.2526881v11.7980702h-4.271715v-2.8252084h-4.136105v2.8252084h-4.407325v-11.7980702c0-1.3184306 1.004082-4.0468495 3.946899-4.197411l.257011-.0064991zm-24.147177-.0027581 8.580186.0005749c.179372.0196801 4.753355.5702841 4.753355 5.5438436s-3.775694 5.3947112-3.92376 5.4093147l-.004472.0004216 5.00569 5.0505836h-6.374959l-3.726209-3.8608906v3.8608906h-4.309831zm22.418634-2.6971669.033418.0329283s-.384228.27122-.791058.610245c-12.837747-9.4927002-20.680526-5.0175701-23.144107-3.8196818-11.187826 6.2428065-7.954768 21.5678895-7.888988 21.8737669l.001006.0046469h-17.855317s.67805-6.6900935 5.4244-14.600677c4.74635-7.9105834 12.837747-13.9000252 19.414832-14.4876686 12.681632-1.2703535 24.110975 9.7062594 24.805814 10.3864403zm-31.111679 14.1815719 2.44098.881465c.113008.8852319.273103 1.7233771.441046 2.4882761l.101394.4499406-2.7122-.9718717c-.113009-.67805-.226017-1.6499217-.27122-2.84781zm31.506724-7.6619652h-1.514312c-1.128029 0-1.333125.5900716-1.370415.8046431l-.007251.056292-.000906.0152319-.00013 3.9153864h4.136105l-.000316-3.916479c-.004939-.0795522-.08331-.8750744-1.242775-.8750744zm-50.492125.339025 2.599192.94927c-.316423.731729-.719369 1.6711108-1.011998 2.4093289l-.118085.3028712-2.599192-.94927c.226017-.610245.700652-1.7403284 1.130083-2.7122001zm35.445121-.1434449h-3.456844v3.6588673h3.434397s.98767-.3815997.98767-1.8406572-.965223-1.8182101-.965223-1.8182101zm-15.442645-.7606218 1.62732 1.2882951c-.180814.705172-.318232 1.410344-.412255 2.115516l-.06238.528879-1.830735-1.4465067c.180813-.81366.384228-1.6499217.67805-2.4861834zm4.000495-6.3058651 1.017075 1.5369134c-.39779.4158707-.766649.8317413-1.095006 1.2707561l-.238493.3339623-1.08488-1.6273201c.40683-.5198383.881465-1.0396767 1.401304-1.5143117zm-16.182794-3.3450467 1.604719 1.4013034c-.40683.4237812-.800947.8729894-1.172815 1.3285542l-.364099.4569775-1.740328-1.4917101c.519838-.5650416 1.08488-1.1300833 1.672523-1.695125zm22.398252-.0904067.497237 1.4917101c-.524359.162732-1.048717.3688592-1.573076.6068095l-.393269.1842488-.519838-1.559515c.565041-.2486184 1.22049-.4972367 1.988946-.7232534zm5.28879-.54244c.578603.0361627 1.171671.1012555 1.779204.2068505l.458361.0869712-.090406 1.4013034c-.596684-.1265694-1.193368-.2097435-1.790052-.2495224l-.447513-.0216976zm-18.555968-6.2380601 1.017075 1.559515c-.440733.2203663-.868752.4661594-1.303128.7278443l-.437201.2666291-1.039676-1.5821167c.610245-.3616267 1.197888-.67805 1.76293-.9718717zm18.601172-.8588633c1.344799.3842283 1.923513.6474959 2.155025.7707625l.037336.0202958-.090406 1.5143117c-.482169-.1958811-.964338-.381717-1.453204-.5575078l-.739158-.2561522zm-8.633837-1.3334984.452033 1.3787017h-.226016c-.491587 0-.983173.0127134-1.474759.0476754l-.491587.0427313-.429431-1.3334984c.745855-.0904067 1.469108-.13561 2.16976-.13561z" transform="translate(-329 19)"/></svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

+1
View File
@@ -15,6 +15,7 @@
"@hono/vite-build": "^1.1.0",
"@hono/vite-dev-server": "^0.17.0",
"@types/node": "^20.11.17",
"typescript": "^5.6.2",
"vite": "^5.4.2"
}
}
+109
View File
@@ -0,0 +1,109 @@
import type { AppType } from '.'
import { createBrowserClient } from '@supabase/ssr'
import { hc } from 'hono/client'
import { useEffect, useState } from 'hono/jsx'
import { render } from 'hono/jsx/dom'
const client = hc<AppType>('/')
const supabase = createBrowserClient(
import.meta.env.VITE_SUPABASE_URL!,
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY!
)
function App() {
const [user, setUser] = useState<null | { id: string }>(null)
// Check client-side if user is logged in:
useEffect(() => {
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((event, session) => {
console.log('Auth event:', event)
if (event === 'SIGNED_OUT') {
setUser(null)
} else {
setUser(session?.user!)
}
})
return () => subscription.unsubscribe()
}, [])
return (
<>
<h1>Hono Supabase Auth Example!</h1>
<h2>Sign in</h2>
{!user ? (
<SignIn />
) : (
<form method="post" action="/signout">
<button type="submit">Sign out!</button>
</form>
)}
<h2>Example of API fetch()</h2>
<UserDetailsButton />
<h2>Example of database read</h2>
<p>Sign in anonymously, then open the instruments list.</p>
<a href="/instruments">Get instruments</a>
</>
)
}
function SignIn() {
return (
<>
<p>
Read about and enable{' '}
<a href="https://supabase.com/docs/guides/auth/auth-anonymous" target="_blank">
anonymous sign-ins here!
</a>
</p>
<button
type="button"
onClick={async () => {
const { data, error } = await supabase.auth.signInAnonymously()
if (error) return console.error('Error signing in:', error.message)
console.log('Signed in client-side!')
alert('Signed in anonymously! User id: ' + data?.user?.id)
}}
>
Anonymous sign in
</button>
</>
)
}
const UserDetailsButton = () => {
const [response, setResponse] = useState<string | null>(null)
const handleClick = async () => {
const response = await client.api.user.$get()
const data = await response.json()
const headers = Array.from(response.headers.entries()).reduce<Record<string, string>>(
(acc, [key, value]) => {
acc[key] = value
return acc
},
{}
)
const fullResponse = {
url: response.url,
status: response.status,
headers,
body: data,
}
setResponse(JSON.stringify(fullResponse, null, 2))
}
return (
<div>
<button type="button" onClick={handleClick}>
Get My User Details
</button>
{response && <pre>{response}</pre>}
</div>
)
}
const root = document.getElementById('root')!
render(<App />, root)
+38 -9
View File
@@ -1,16 +1,19 @@
import { Hono } from 'hono'
import { csrf } from 'hono/csrf'
import { getSupabase, supabaseMiddleware } from './middleware/auth.middleware'
const app = new Hono()
app.use('*', csrf())
app.use('*', supabaseMiddleware())
app.get('/api/user', async (c) => {
const routes = app.get('/api/user', async (c) => {
const supabase = getSupabase(c)
const { data, error } = await supabase.auth.getClaims()
if (error) console.log('error', error)
if (!data?.user) {
if (!data?.claims) {
return c.json({
message: 'You are not logged in.',
})
@@ -18,23 +21,49 @@ app.get('/api/user', async (c) => {
return c.json({
message: 'You are logged in!',
userId: data.user,
userId: data.claims.sub,
})
})
app.get('/signout', async (c) => {
app.post('/signout', async (c) => {
const supabase = getSupabase(c)
await supabase.auth.signOut()
console.log('Signed out server-side!')
return c.redirect('/')
return c.redirect('/', 303)
})
// Retrieve data with RLS enabled. The signed in user's auth token is automatically sent.
app.get('/countries', async (c) => {
app.get('/instruments', async (c) => {
const supabase = getSupabase(c)
const { data, error } = await supabase.from('countries').select('*')
if (error) console.log(error)
const { data, error } = await supabase.from('instruments').select('*')
if (error) {
console.error(error)
return c.json({ error: error.message }, 500)
}
return c.json(data)
})
export type AppType = typeof routes
app.get('/', (c) => {
return c.html(
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta content="width=device-width, initial-scale=1" name="viewport" />
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css" />
{import.meta.env.PROD ? (
<script type="module" src="/static/client.js" />
) : (
<script type="module" src="/src/client.tsx" />
)}
</head>
<body>
<div id="root" />
</body>
</html>
)
})
export default app
@@ -3,6 +3,7 @@ import { SupabaseClient } from '@supabase/supabase-js'
import type { Context, MiddlewareHandler } from 'hono'
import { env } from 'hono/adapter'
import { setCookie } from 'hono/cookie'
import type { CookieOptions } from 'hono/utils/cookie'
import type { Database } from '../database.types'
@@ -17,22 +18,23 @@ export const getSupabase = (c: Context) => {
}
type SupabaseEnv = {
SUPABASE_URL: string
SUPABASE_PUBLISHABLE_KEY: string
VITE_SUPABASE_URL: string
VITE_SUPABASE_PUBLISHABLE_KEY: string
}
export const supabaseMiddleware = (): MiddlewareHandler => {
return async (c, next) => {
const supabaseEnv = env<SupabaseEnv>(c)
const supabaseUrl = supabaseEnv.SUPABASE_URL
const supabasePublishableKey = supabaseEnv.SUPABASE_PUBLISHABLE_KEY
const supabaseUrl = supabaseEnv.VITE_SUPABASE_URL ?? import.meta.env.VITE_SUPABASE_URL
const supabasePublishableKey =
supabaseEnv.VITE_SUPABASE_PUBLISHABLE_KEY ?? import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
if (!supabaseUrl) {
throw new Error('SUPABASE_URL missing!')
throw new Error('VITE_SUPABASE_URL missing!')
}
if (!supabasePublishableKey) {
throw new Error('SUPABASE_PUBLISHABLE_KEY missing!')
throw new Error('VITE_SUPABASE_PUBLISHABLE_KEY missing!')
}
const supabase = createServerClient(supabaseUrl, supabasePublishableKey, {
@@ -40,8 +42,11 @@ export const supabaseMiddleware = (): MiddlewareHandler => {
getAll() {
return parseCookieHeader(c.req.header('Cookie') ?? '')
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) => setCookie(c, name, value, options))
setAll(cookiesToSet, cacheHeaders) {
cookiesToSet.forEach(({ name, value, options }) =>
setCookie(c, name, value, options as CookieOptions)
)
Object.entries(cacheHeaders).forEach(([key, value]) => c.header(key, value))
},
},
})
+12
View File
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"types": ["vite/client"],
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx"
}
}
+33
View File
@@ -0,0 +1,33 @@
import devServer from '@hono/vite-dev-server'
import { defineConfig } from 'vite'
// Change the import to use your runtime specific build
import build from '@hono/vite-build/node'
export default defineConfig(({ mode }) => {
if (mode === 'client')
return {
esbuild: {
jsxImportSource: 'hono/jsx/dom', // Optimized for hono/jsx/dom
},
build: {
rollupOptions: {
input: './src/client.tsx',
output: {
entryFileNames: 'static/client.js',
},
},
},
}
return {
plugins: [
build({
entry: 'src/index.tsx',
}),
devServer({
entry: 'src/index.tsx',
}),
],
}
})