Add to Existing Project
Supabase Modules have been designed with Next in mind. So after setting up your Next application or in your existing Next application, here is what you will need:
Before proceeding
These instructions are based on a Next 14 application. More frameworks coming soon.
1. Installing dependencies
pnpm add @tanstack/react-query @supabase/ssr @supabase/supabase-js
Supabase CLI
To run the entire Supabase Stack locally on your machine, you will have to decide whether you want to add the Supabase CLI as a dev dependency, execute it using your package manager or install it globally using Homebrew
pnpm add -D supabase
pnpm dlx supabase <command>
brew install supabase/tap/supabase
You will also need to update your package.json
scripts to use Supabase CLI:
"scripts": {
"db:init": "supabase init",
"db:start": "supabase start",
"db:stop": "supabase stop",
"db:reset": "supabase db reset",
"db:gen-types": "supabase gen types typescript --local > database/types/supabase.ts"
}
2. Initialize or scaffold your Supabase project
You can chose whether you want to start with a new Supabase project or if you want to scaffold your Supabase project files:
pnpm db:init
supabase init
degit webscopeio/supabase-modules/apps/next/supabase supabase
From either of these you should have a /supabase
directory in your project with at least config.toml
and seed.sql
files.
INFO
When you initialize a Supabase projecet. You do not need to generate VS Code settings for Deno.
3. Set environment variables
Update or create an .env.local
file to store your environment variables.
# Since .env is gitignored, you can use .env.example to build a new `.env` file when you clone the repo.
# Keep this file up-to-date when you add new variables to \`.env\`.
# These examples are for development use only
NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0
The .env.example
file above contains the environment variables that you can use for local development.
To generate these environment variables you have to run Supabase locally first before development. Read more on Your Supabase Instance.
4. Add Query and API Route Handler to your project
TanStack Query
To use TanStack Query you need to set a QueryClientProvider
. Typically you would add this to your list of providers or create a provider if you don't have one already.
"use client"
import * as React from "react"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { ThemeProvider as NextThemesProvider } from "next-themes"
export const Providers: React.FC<React.PropsWithChildren> = ({ children }) => {
const [queryClient] = React.useState(
() =>
new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000,
},
},
})
)
return (
<QueryClientProvider client={queryClient}>
<NextThemesProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
{children}
</NextThemesProvider>
</QueryClientProvider>
)
}
This provider has to be included in the project code. In a Next 13 application this would be in the mainlayout.tsx
file. For more, see TanStack Query Next.js app with streaming.
API Route Handler
Chances are that you will need this route handler.
import { NextResponse, type NextRequest } from "next/server"
import { type EmailOtpType } from "@supabase/supabase-js"
import { createClient } from "@/database/client/server"
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url)
const type = searchParams.get("type") as EmailOtpType | null
const token_hash = searchParams.get("token_hash")
const next = searchParams.get("next") ?? "/auth"
const redirectTo = request.nextUrl.clone()
redirectTo.pathname = next
redirectTo.searchParams.delete("next")
redirectTo.searchParams.delete("token_hash")
redirectTo.searchParams.delete("type")
if (token_hash && type) {
const supabase = createClient()
const { error } = await supabase.auth.verifyOtp({
type,
token_hash,
})
if (error) {
redirectTo.pathname = "/auth"
redirectTo.searchParams.set(
"error",
JSON.stringify({ message: error.message, status: error.status || 401 })
)
}
if (type === "recovery") {
redirectTo.pathname = "/auth/update"
}
return NextResponse.redirect(redirectTo)
}
}
5. Start your development server
Before proceeding
To work with a local Supabase Instance you need to run a database container with a running docker daemon. We recommend getting Docker. You can find instructions on Get Docker
pnpm db:start && pnpm dev
pnpm dev
🎉 Congratulations!
You are done! See Installation to install individual Modules. Remember to run pnpm db:stop
to save resources once you are done working with your local Supabase Instance.
Recommendations
It is recommended to also use TanStack's ESLint Plugin Query to help you catch bugs and inconsistencies while you code.
pnpm add -D @tanstack/eslint-plugin-query
Make sure to read their Usage Instructions for setup.
ESLint Configuration Example
Here is an example of a simple setup for a Next TypeScript React project:
- First install the dev dependencies (here we're included all of the dependencies for the config):
pnpm add -D eslint eslint-config-next @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-prettier eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-tailwindcss
- Then configure your
eslintc.json
{
"extends": [
"next/core-web-vitals",
"eslint:recommended",
"prettier",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:@tanstack/eslint-plugin-query/recommended",
"plugin:tailwindcss/recommended"
],
"plugins": ["@typescript-eslint", "react", "react-hooks", "tailwindcss"],
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": true,
"ecmaFeatures": {
"jsx": true
}
},
"rules": {
"@typescript-eslint/consistent-type-definitions": "off",
"@typescript-eslint/no-misused-promises": [
"error",
{
"checksVoidReturn": {
"attributes": false
}
}
],
"no-console": ["error", { "allow": ["error"] }],
"react/prop-types": "off",
"react/react-in-jsx-scope": "off",
"tailwindcss/no-custom-classname": "off",
"tailwindcss/classnames-order": "off"
},
"settings": {
"tailwindcss": {
"callees": ["cn", "cva"],
"config": "tailwind.config.ts"
},
"react": {
"version": "detect"
}
},
"ignorePatterns": [
"/lib/env.ts",
"/postcss.config.js",
"/database/types/supabase.ts"
]
}