diff --git a/apps/reference/docs/guides/auth/auth-helpers/index.mdx b/apps/reference/docs/guides/auth/auth-helpers/index.mdx
index bcb52c6a759..ea3bb8222ee 100644
--- a/apps/reference/docs/guides/auth/auth-helpers/index.mdx
+++ b/apps/reference/docs/guides/auth/auth-helpers/index.mdx
@@ -46,6 +46,18 @@ A collection of framework-specific Auth utilities for working with Supabase.
style={{ height: '100%' }}
/>
+ {/* Remix */}
+
+
+
diff --git a/apps/reference/docs/guides/auth/auth-helpers/remix.mdx b/apps/reference/docs/guides/auth/auth-helpers/remix.mdx
new file mode 100644
index 00000000000..029b876d7b7
--- /dev/null
+++ b/apps/reference/docs/guides/auth/auth-helpers/remix.mdx
@@ -0,0 +1,910 @@
+---
+id: remix
+title: Supabase Auth with Remix
+description: Authentication helpers for loaders and actions in Remix.
+sidebar_label: 'Remix'
+---
+
+import Tabs from '@theme/Tabs'
+import TabItem from '@theme/TabItem'
+
+This submodule provides convenience helpers for implementing user authentication in Remix applications.
+
+## Install the Remix helper library
+
+
+
+
+
+```sh
+npm install @supabase/auth-helpers-remix
+```
+
+This library supports the following tooling versions:
+
+- Remix: `>=1.7.2`
+
+
+
+
+```sh
+yarn add @supabase/auth-helpers-remix
+```
+
+This library supports the following tooling versions:
+
+- Remix: `>=1.7.2`
+
+
+
+
+## Set up environment variables
+
+Retrieve your project URL and anon key in your project's [API settings](https://app.supabase.com/project/_/settings/api) in the Dashboard to set up the following environment variables. For local development you can set them in a `.env` file. See an [example](https://github.com/supabase/auth-helpers/blob/main/examples/remix/.env.example).
+
+```bash title=".env"
+SUPABASE_URL=YOUR_SUPABASE_URL
+SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
+```
+
+## Loader
+
+
+
+
+Loader functions run on the server immediately before the component is rendered. They respond to all GET requests on a route. You can create an authenticated Supabase client by calling the `createSupabaseClient` function and passing it your `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and a `Request` and `Response`.
+
+```jsx
+import { json } from '@remix-run/node' // change this import to whatever runtime you are using
+import { createSupabaseClient } from '@supabase/auth-helpers-remix'
+
+export const loader = async ({ request }) => {
+ const response = new Response()
+ // an empty response is required for the auth helpers
+ // to set cookies to manage auth
+
+ const supabaseClient = createSupabaseClient(
+ process.env.SUPABASE_URL,
+ process.env.SUPABASE_ANON_KEY,
+ { request, response }
+ )
+
+ const { data } = await supabaseClient.from('test').select('*')
+
+ // in order for the set-cookie header to be set,
+ // headers must be returned as part of the loader response
+ return json(
+ { data },
+ {
+ headers: response.headers,
+ }
+ )
+}
+```
+
+> Supabase will set cookie headers to manage the user's auth session, therefore, the `response.headers` must be returned from the `Loader` function.
+
+
+
+
+Loader functions run on the server immediately before the component is rendered. You can create an authenticated Supabase client by calling the `createSupabaseClient` function and passing it your `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and a `Request` and `Response`.
+
+```jsx
+import { LoaderFunction, json } from '@remix-run/node' // change this import to whatever runtime you are using
+import { createSupabaseClient } from '@supabase/auth-helpers-remix'
+
+export const loader: LoaderFunction = async ({
+ request,
+}: {
+ request: Request,
+}) => {
+ const response = new Response()
+ const supabaseClient = createSupabaseClient(
+ process.env.SUPABASE_URL,
+ process.env.SUPABASE_ANON_KEY,
+ { request, response }
+ )
+
+ const { data } = await supabaseClient.from('test').select('*')
+
+ return json(
+ { data },
+ {
+ headers: response.headers,
+ }
+ )
+}
+```
+
+> Supabase will set cookie headers to manage the user's auth session, therefore, the `response.headers` must be returned from the `Loader` function.
+
+
+
+
+## Action
+
+
+
+
+Action functions run on the server and respond to HTTP requests to a route, other than GET - POST, PUT, PATCH, DELETE etc. You can create an authenticated Supabase client by calling the `createSupabaseClient` function and passing it your `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and a `Request` and `Response`.
+
+```jsx
+import { json } from '@remix-run/node' // change this import to whatever runtime you are using
+import { createSupabaseClient } from '@supabase/auth-helpers-remix'
+
+export const action = async ({ request }) => {
+ const response = new Response()
+
+ const supabaseClient = createSupabaseClient(
+ process.env.SUPABASE_URL,
+ process.env.SUPABASE_ANON_KEY,
+ { request, response }
+ )
+
+ const { data } = await supabaseClient.from('test').select('*')
+
+ return json(
+ { data },
+ {
+ headers: response.headers,
+ }
+ )
+}
+```
+
+> Supabase will set cookie headers to manage the user's auth session, therefore, the `response.headers` must be returned from the `Action` function.
+
+
+
+
+Action functions run on the server and respond to HTTP requests to a route, other than GET - POST, PUT, PATCH, DELETE etc. You can create an authenticated Supabase client by calling the `createSupabaseClient` function and passing it your `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and a `Request` and `Response`.
+
+```jsx
+import { ActionFunction, json } from '@remix-run/node' // change this import to whatever runtime you are using
+import { createSupabaseClient } from '@supabase/auth-helpers-remix'
+
+export const action: ActionFunction = async ({
+ request,
+}: {
+ request: Request,
+}) => {
+ const response = new Response()
+
+ const supabaseClient = createSupabaseClient(
+ process.env.SUPABASE_URL,
+ process.env.SUPABASE_ANON_KEY,
+ { request, response }
+ )
+
+ const { data } = await supabaseClient.from('test').select('*')
+
+ return json(
+ { data },
+ {
+ headers: response.headers,
+ }
+ )
+}
+```
+
+> Supabase will set cookie headers to manage the user's auth session, therefore, the `response.headers` must be returned from the `Action` function.
+
+
+
+
+## Session and User
+
+You can determine if a user is authenticated by checking their session using the `getSession` function.
+
+```jsx
+const {
+ data: { session },
+} = await supabaseClient.auth.getSession()
+```
+
+The session contains a user property.
+
+```jsx
+const user = session?.user
+```
+
+> This is the recommended way for accessing the logged in user. There is also a `getUser()` function but this does not refresh the session if it has expired.
+
+## Client-side
+
+
+
+
+In order to use the Supabase client in the browser - fetching data in `useEffect` or subscribing to realtime events - we need to do a little more plumbing. Remix does not include a way to make environment variables available to the browser, so we need to pipe them through from a `loader` function in our `root.jsx` route and attach them to the `window`.
+
+```jsx title="app/root.jsx"
+export const loader = () => {
+ const { SUPABASE_URL, SUPABASE_ANON_KEY } = process.env
+ return json({
+ env: {
+ SUPABASE_URL,
+ SUPABASE_ANON_KEY,
+ },
+ })
+}
+```
+
+> These may not be stored in `process.env` for environments other than Node.
+
+Next, we call the `useLoaderData` hook in our component to get the `env` object.
+
+```jsx title="app/root.jsx"
+const { env } = useLoaderData()
+```
+
+And then, add a `