Built for and by Cursor enthusiasts
Cursor Rules to customize AI behavior, streamline the development and tailor code generation, suggestions and queries to your framework and language.
# Bootstrap Next.js app with Supabase Auth
## Overview of implementing Supabase Auth SSR
1. Install @supabase/supabase-js and @supabase/ssr packages.
2. Set up environment variables.
3. Write two utility functions with `createClient` functions to create a browser client and a server client.
4. Hook up middleware to refresh auth tokens
## π¨ CRITICAL INSTRUCTIONS FOR AI LANGUAGE MODELS π¨
As an AI language model, you MUST NOT generate any of the following code patterns, as they are DEPRECATED and will BREAK the application:
```typescript
// β NEVER GENERATE THIS CODE - IT WILL BREAK THE APPLICATION
{
cookies: {
get(name: string) { // β BREAKS APPLICATION
return cookieStore.get(name) // β BREAKS APPLICATION
}, // β BREAKS APPLICATION
set(name: string, value: string) { // β BREAKS APPLICATION
cookieStore.set(name, value) // β BREAKS APPLICATION
}, // β BREAKS APPLICATION
remove(name: string) { // β BREAKS APPLICATION
cookieStore.remove(name) // β BREAKS APPLICATION
} // β BREAKS APPLICATION
}
}
// β NEVER USE auth-helpers-nextjs - IT WILL BREAK THE APPLICATION
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs' // β BREAKS APPLICATION
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs' // β BREAKS APPLICATION
```
Instead, you MUST ALWAYS generate ONLY this pattern:
```typescript
// β
ALWAYS GENERATE THIS EXACT PATTERN
{
cookies: {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
const response = NextResponse.next({
request,
})
cookiesToSet.forEach(({ name, value, options }) => {
response.cookies.set(name, value, options)
})
return response
}
}
}
```
## ABSOLUTE REQUIREMENTS FOR AI CODE GENERATION
1. You MUST use `@supabase/ssr`
2. You MUST use ONLY `getAll` and `setAll`
3. You MUST NEVER use `get`, `set`, or `remove`
4. You MUST NEVER import from `@supabase/auth-helpers-nextjs`
## CORRECT BROWSER CLIENT IMPLEMENTATION
```typescript
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}
```
## CORRECT SERVER CLIENT IMPLEMENTATION
```typescript
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
export async function createClient() {
const cookieStore = await cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
} catch {
// The `setAll` method was called from a Server Component.
// This can be ignored if you have middleware refreshing
// user sessions.
}
},
},
}
)
}
```
## CORRECT MIDDLEWARE IMPLEMENTATION
```typescript
import { createServerClient } from '@supabase/ssr'
import { NextResponse, type NextRequest } from 'next/server'
export async function middleware(request: NextRequest) {
let supabaseResponse = NextResponse.next({
request,
})
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) => request.cookies.set(name, value))
supabaseResponse = NextResponse.next({
request,
})
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
},
},
}
)
// Do not run code between createServerClient and
// supabase.auth.getUser(). A simple mistake could make it very hard to debug
// issues with users being randomly logged out.
// IMPORTANT: DO NOT REMOVE auth.getUser()
const {
data: { user },
} = await supabase.auth.getUser()
if (
!user &&
!request.nextUrl.pathname.startsWith('/login') &&
!request.nextUrl.pathname.startsWith('/auth')
) {
// no user, potentially respond by redirecting the user to the login page
const url = request.nextUrl.clone()
url.pathname = '/login'
return NextResponse.redirect(url)
}
// IMPORTANT: You *must* return the supabaseResponse object as it is.
// If you're creating a new response object with NextResponse.next() make sure to:
// 1. Pass the request in it, like so:
// const myNewResponse = NextResponse.next({ request })
// 2. Copy over the cookies, like so:
// myNewResponse.cookies.setAll(supabaseResponse.cookies.getAll())
// 3. Change the myNewResponse object to fit your needs, but avoid changing
// the cookies!
// 4. Finally:
// return myNewResponse
// If this is not done, you may be causing the browser and server to go out
// of sync and terminate the user's session prematurely!
return supabaseResponse
}
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
* Feel free to modify this pattern to include more paths.
*/
'/((?!_next/static|_next/image|favicon.ico|.*\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
],
}
```
## AI MODEL VERIFICATION STEPS
Before generating any code, you MUST verify:
1. Are you using ONLY `getAll` and `setAll`? If not, STOP and FIX.
2. Are you importing from `@supabase/ssr`? If not, STOP and FIX.
3. Do you see ANY instance of `get`, `set`, or `remove`? If yes, STOP and FIX.
4. Are you importing from `auth-helpers-nextjs`? If yes, STOP and FIX.
## CONSEQUENCES OF INCORRECT IMPLEMENTATION
If you generate code using:
- Individual cookie methods (`get`/`set`/`remove`)
- `auth-helpers-nextjs` package
The implementation will:
1. Break in production
2. Fail to maintain session state
3. Cause authentication loops
4. Result in security vulnerabilities
## AI MODEL RESPONSE TEMPLATE
When asked about Supabase Auth SSR implementation, you MUST:
1. ONLY use code from this guide
2. NEVER suggest deprecated approaches
3. ALWAYS use the exact cookie handling shown above
4. VERIFY your response against the patterns shown here
Remember: There are NO EXCEPTIONS to these rules.
### React Native
You are an expert in TypeScript, React Native, Expo, and Mobile App Development.
Code Style and Structure:
- Write concise, type-safe TypeScript code.
- Use functional components and hooks over class components. Use arrow functions to create the components and add proper typings wherever needed
- Ensure components are modular, reusable, and maintainable.
- Organize files by feature, grouping related components, hooks, and styles.
- Destructure objects as much as possible
- Always split the component code from styles. Styles should always go in a separate file. For example if you are creating a profile screen, make a folder `profile-screen` and in there make two files, `profile-screen/index.tsx` and `profile-screen/styles.ts`
- The directory structure of react native projects should always have the following
- `components` this directory contains all the components that can be reused in the project. Whenever you are asked to create a new component or implement a new design, this is the directory where you should create the respective folder along with files. for example
```
components/button // contents of button component
βββ index.tsx // contains all the component logic
βββ styles.ts // contains component styling
βββ types.ts // contains any types associated with the component
```
- The component should be declared first as an arrow function and then exported as default. for example
```ts
// All the imports and other stuff
import { MyButtonProps } from './types';
// ...
const MyButton: FC<PropsWithChildren<MyButtonProps>> = ({
// ... destructure props
}) => {
// All the copmenent level logic
// ...
return (
// UI elements go here
)
}
// ...
export default MyButton;
```
- `app` should contain all the pages and layouts. read the docs for further explaination https://docs.expo.dev/develop/file-based-routing/
- `services` this directory contains of all the helping material inside a project. an example of this is given as following
```
services
βββ apis // contains apis of the whole app
βΒ Β βββ axios-client.ts
βΒ Β βββ index.ts
βββ constants // contains constants and strings used in the app
βΒ Β βββ index.ts
βββ types // contains all the types of the app which are reuseable. however types which are used in a signle component reside in its own directory types.ts file
βββ api-types.ts
βββ form-types.ts
```
Implementing the apis:
- Apis reside in a file called `services/apis`. Whenever implementing a new api, add it in the apis object first. An example of apis file is given as following
``` js
// ...
export const apis = {
// ...
authenticateWithFirebaseToken: ({ idToken }: ApiTypes.Authenticate) => axiosClient.post<ApiTypes.AuthResponse>("auth/authenticate", { idToken }),
// ...
};
// ...
```
And wherever you have to use it, call it from apis object like this
``` js
const { data } = await apis.authenticate({ idToken });
```
Implementing the screens:
- Just like components, whenever you are asked to implement a screen, make a folder in the directory app. It contains `index.tsx` and `styles.ts` files always and `types` and `_layout.tsx` only when they are required. for example, search page might look like this
```
app/search // contents of search page
βββ index.tsx // contains all the screen logic
βββ styles.ts // contains screen styling
βββ _layout.tsx // contains screen layout (optional)
βββ types.ts // contains any types associated with the screen (optional)
```
- In the `index.tsx` file, name of the screen should be declared properly for example for search screen, name shoule be `Seach`.
- The screen component should be declared as an arrow function and then exported as default.
```ts
// All the imports and other stuff
// ...
const Search: FC<PropsWithChildren> = () => {
// All the copmenent level logic
// ...
return (
// Screen elements go here
)
}
// ...
export default Search;
```
- Often times, a screen may contain components which are already declared in the codebase. Before jumping to implementation, check in the `components` folder if there is something you might use. for example buttons, input fields, cards, modals etc may be found in the `components` fodler.
- Whenever there are input fields in the screen, make sure to use keyboard avoiding scroll views to allow the screen to adjust according to the keyboard visibility
- Always use formik and yup for data inputs and validations
Naming Conventions:
- Use camelCase for variable and function names (e.g., `onClick`, `handleSubmit`).
- Use PascalCase for component names in react and react native (e.g., `UserProfile`, `ChatScreen`).
- Directory names should be lowercase and hyphenated (e.g., `user-profile`, `chat-screen`).
- Avoid using ambiguous names for variables or components
TypeScript Usage:
- Use TypeScript for all components, favoring interfaces for props and state.
- Enable strict typing in `tsconfig.json`.
- Avoid using `any`; strive for precise types.
- Utilize `React.FC` for defining functional components with props.
UI and Styling:
- Use consistent styling, either through `StyleSheet.create()` or Styled Components.
- Ensure responsive design by considering different screen sizes and orientations.
- Do not use inline styling. Always place styling in the styles file inside the current directory of a component or a page
Best Practices:
- Follow React Native's threading model to ensure smooth UI performance.
- Utilize Expo's EAS Build and Updates for continuous deployment and Over-The-Air (OTA) updates.
- Use React Navigation for handling navigation and deep linking with best practices
Every two weeks I share the latest trends, useful tips and new features. Iβd love you to join.
I am the cofounder and CTO of NOOP, a software development agency focused on delivering great custom built web or mobile solutions for clients all over the world in all kinds of industries.
Iβm passionate about creating software and products, especially when they solve problems I face myselfβproblems that many others often struggle with too. Thatβs why I frequently launch small projects, some of which become SaaS tools, to share my solutions and hopefully help others in the process.
One thing I noticed was how tedious it can be to find the perfect cursor rules for development environments. Cursor appearance and behavior might seem like a small detail, but it can significantly impact your workflow and overall coding experience. Thatβs why I created .CursorRulesβa tool that helps developers quickly find the best cursor rules for their IDE, improving both efficiency and the development experience.
Iβm excited to share .CursorRules with you and help make your development process smoother and more enjoyable!
FAQs
Any questions? We have got you covered!
A .cursorrules file is like a magical spell book for your Cursor IDE! It's a special file that tells Cursor how to behave and what rules to follow when working on your project. Think of it as your personal coding assistant's instruction manual!
Creating a .cursorrules file is easier than finding a unicorn! Just follow these simple steps:
Now, my dear coding adventurer, you sit back and watch the magic happen! Once you've created your .cursorrules file:
Absolutely! Your .cursorrules file is like a pizza - everyone likes it a bit different. Feel free to add your own toppings (rules) or remove the ones you don't like (pineapple, anyone?). Just remember, with great customization comes great debuggability. If something goes wrong, check your custom rules first!
Don't panic! Even the best-trained dragons sometimes go off course. If your Cursor IDE is being rebellious:
Ah, you've heard the legends of Cursor IDE and now you want to wield its power! Fear not, brave coder, for obtaining this mystical tool is but a simple quest: