AI Prompt: Bootstrap Next.js v16 app with Supabase Auth

How to use

Copy the prompt to a file in your repo.

Use the "include file" feature from your AI tool to include the prompt when chatting with your AI assistant. For example, with GitHub Copilot, use #<filename>, in Cursor, use @Files, and in Zed, use /file.

Prompt

1
# Bootstrap Next.js v16 app with Supabase Auth
2

3
## Overview of implementing Supabase Auth SSR
4

5
1. Install @supabase/supabase-js and @supabase/ssr packages.
6
2. Set up environment variables.
7
3. Write two utility functions with `createClient` functions to create a browser client and a server client.
8
4. Hook up Proxy to refresh auth tokens

10
## 🚨 CRITICAL INSTRUCTIONS FOR AI LANGUAGE MODELS 🚨
12
As an AI language model, you MUST NOT generate any of the following code patterns, as they are DEPRECATED and will BREAK the application:
14
```typescript
15
// ❌ NEVER GENERATE THIS CODE - IT WILL BREAK THE APPLICATION
16
{
17
cookies: {
18
    get(name: string) {                 // ❌ BREAKS APPLICATION
19
      return cookieStore.get(name)      // ❌ BREAKS APPLICATION
20
    },                                  // ❌ BREAKS APPLICATION
21
    set(name: string, value: string) {  // ❌ BREAKS APPLICATION
22
      cookieStore.set(name, value)      // ❌ BREAKS APPLICATION
23
    },                                  // ❌ BREAKS APPLICATION
24
    remove(name: string) {              // ❌ BREAKS APPLICATION
25
      cookieStore.remove(name)          // ❌ BREAKS APPLICATION
26
    }                                   // ❌ BREAKS APPLICATION
27
}
28
}
30
// ❌ NEVER USE auth-helpers-nextjs - IT WILL BREAK THE APPLICATION
31
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'  // ❌ BREAKS APPLICATION
32
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'  // ❌ BREAKS APPLICATION
33
```
35
Instead, you MUST ALWAYS generate ONLY this pattern:
37
```typescript
38
// ✅ ALWAYS GENERATE THIS EXACT PATTERN
39
{
40
cookies: {
41
    getAll() {
42
      return cookieStore.getAll()
43
    },
44
    setAll(cookiesToSet, headers) {
45
      const response = NextResponse.next({
46
        request,
47
      })
48

49
      cookiesToSet.forEach(({ name, value, options }) => {
50
        response.cookies.set(name, value, options)
51
      })
52
      Object.entries(headers).forEach(([key, value]) =>
53
        response.headers.set(key, value)
54
      )
55

56
      return response
57
    }
58
}
59
}
60
```
62
## ABSOLUTE REQUIREMENTS FOR AI CODE GENERATION
64
1. You MUST use `@supabase/ssr`
65
2. You MUST use ONLY `getAll` and `setAll`
66
3. You MUST NEVER use `get`, `set`, or `remove`
67
4. You MUST NEVER import from `@supabase/auth-helpers-nextjs`
69
## CORRECT BROWSER CLIENT IMPLEMENTATION
71
```typescript
72
import { createBrowserClient } from '@supabase/ssr'
73

74
export function createClient() {
75
return createBrowserClient(
76
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
77
    process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
78
)
79
}
80
```
82
## CORRECT SERVER CLIENT IMPLEMENTATION
84
```typescript
85
import { createServerClient } from '@supabase/ssr'
86
import { cookies } from 'next/headers'
87

88
export async function createClient() {
89
const cookieStore = await cookies()
90

91
return createServerClient(
92
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
93
    process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
94
    {
95
      cookies: {
96
        getAll() {
97
          return cookieStore.getAll()
98
        },
99
        setAll(cookiesToSet, _headers) {
100
          try {
101
            cookiesToSet.forEach(({ name, value, options }) =>
102
              cookieStore.set(name, value, options)
103
            )
104
          } catch {
105
            // The `setAll` method was called from a Server Component.
106
            // This can be ignored if you have proxy refreshing
107
            // user sessions.
108
          }
109
        },
110
      },
111
    }
)
}
114
```
116
## CORRECT PROXY IMPLEMENTATION
118
```typescript
119
import { createServerClient } from '@supabase/ssr'
120
import { NextResponse, type NextRequest } from 'next/server'
121

122
export async function proxy(request: NextRequest) {
123
let supabaseResponse = NextResponse.next({
124
    request,
125
})
126

127
const supabase = createServerClient(
128
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
129
    process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
130
    {
131
      cookies: {
132
        getAll() {
133
          return request.cookies.getAll()
134
        },
135
        setAll(cookiesToSet, headers) {
136
          cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value))
137
          supabaseResponse = NextResponse.next({
138
            request,
139
          })
140
          cookiesToSet.forEach(({ name, value, options }) =>
141
            supabaseResponse.cookies.set(name, value, options)
142
          )
143
          Object.entries(headers).forEach(([key, value]) =>
144
            supabaseResponse.headers.set(key, value)
145
          )
146
        },
147
      },
148
    }
149
)
150

151
// Do not run code between createServerClient and
152
// supabase.auth.getUser(). A simple mistake could make it very hard to debug
153
// issues with users being randomly logged out.
154

155
// IMPORTANT: DO NOT REMOVE auth.getUser()
156

157
const {
158
    data: { user },
159
} = await supabase.auth.getUser()
160

161
if (
162
    !user &&
163
    !request.nextUrl.pathname.startsWith('/login') &&
164
    !request.nextUrl.pathname.startsWith('/auth')
165
) {
166
    // no user, potentially respond by redirecting the user to the login page
167
    const url = request.nextUrl.clone()
168
    url.pathname = '/login'
169
    return NextResponse.redirect(url)
170
}
171

172
// IMPORTANT: You *must* return the supabaseResponse object as it is.
173
// If you're creating a new response object with NextResponse.next() make sure to:
174
// 1. Pass the request in it, like so:
175
//    const myNewResponse = NextResponse.next({ request })
176
// 2. Copy over the cookies, like so:
177
//    myNewResponse.cookies.setAll(supabaseResponse.cookies.getAll())
178
// 3. Change the myNewResponse object to fit your needs, but avoid changing
179
//    the cookies!
180
// 4. Finally:
181
//    return myNewResponse
182
// If this is not done, you may be causing the browser and server to go out
183
// of sync and terminate the user's session prematurely!
184

185
return supabaseResponse
186
}
188
export const config = {
189
matcher: [
190
    /*
191     * Match all request paths except for the ones starting with:
192     * - _next/static (static files)
193     * - _next/image (image optimization files)
194     * - favicon.ico (favicon file)
195     * Feel free to modify this pattern to include more paths.
196     */
197
    '/((?!_next/static|_next/image|favicon.ico|.*\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
198
],
199
}
200

AI MODEL VERIFICATION STEPS

204 Before generating any code, you MUST verify: 206

  1. Are you using ONLY getAll and setAll? If not, STOP and FIX. 207
  2. Are you importing from @supabase/ssr? If not, STOP and FIX. 208
  3. Do you see ANY instance of get, set, or remove? If yes, STOP and FIX. 209
  4. Are you importing from auth-helpers-nextjs? If yes, STOP and FIX. 211

CONSEQUENCES OF INCORRECT IMPLEMENTATION

213 If you generate code using: 215

  • Individual cookie methods (get/set/remove) 216
  • auth-helpers-nextjs package 218 The implementation will: 220
  1. Break in production 221
  2. Fail to maintain session state 222
  3. Cause authentication loops 223
  4. Result in security vulnerabilities 225

AI MODEL RESPONSE TEMPLATE

227 When asked about Supabase Auth SSR implementation, you MUST: 229

  1. ONLY use code from this guide 230
  2. NEVER suggest deprecated approaches 231
  3. ALWAYS use the exact cookie handling shown above 232
  4. VERIFY your response against the patterns shown here 234 Remember: There are NO EXCEPTIONS to these rules.