[{"data":1,"prerenderedAt":335},["ShallowReactive",2],{"blog-blueprints/cursor-nextjs-supabase":3},{"id":4,"title":5,"body":6,"category":314,"date":315,"dateModified":316,"description":317,"draft":318,"extension":319,"faq":320,"featured":318,"headerVariant":321,"image":320,"keywords":320,"meta":322,"navigation":323,"ogDescription":324,"ogTitle":320,"path":325,"readTime":326,"schemaOrg":327,"schemaType":328,"seo":329,"sitemap":330,"stem":331,"tags":332,"twitterCard":333,"__hash__":334},"blog/blog/blueprints/cursor-nextjs-supabase.md","Cursor + Next.js + Supabase Security Blueprint",{"type":7,"value":8,"toc":297},"minimark",[9,20,24,30,35,46,51,54,120,124,128,138,142,151,155,159,162,171,180,193,197,202,205,208,211,214,217,220,223,226,244,266,285],[10,11,12],"blueprint-summary",{},[13,14,15,19],"p",{},[16,17,18],"strong",{},"To secure a Cursor + Next.js + Supabase stack,"," you need to: (1) use the correct Supabase client for each context (createBrowserClient for Client Components, createServerClient for Server Components/Actions), (2) enable Row Level Security on all Supabase tables, (3) always verify authentication with auth.getUser() in Server Actions before mutations, (4) never trust user ID from form data - always get it from the authenticated session, and (5) configure middleware to protect authenticated routes. This blueprint covers Next.js App Router client patterns and Server Action security.",[21,22],"blueprint-meta",{"time":23},"2-3 hours",[25,26,27],"tldr",{},[13,28,29],{},"Next.js 14+ with App Router adds complexity to Supabase integration. You need different Supabase clients for Server Components, Server Actions, Route Handlers, and the browser. Enable RLS on all tables, use the server client with service role for admin operations, and always verify authentication in Server Actions. Common AI-generated mistakes include mixing client types and missing auth checks in server code.",[31,32,34],"h3",{"id":33},"platform-guides-checklists","Platform Guides & Checklists",[36,37,42],"pre",{"className":38,"code":40,"language":41},[39],"language-text","      Cursor Security Guide\n\n\n\n      Next.js Security Guide\n\n\n\n      Supabase Security Guide\n\n\n\n      Pre-Launch Checklist\n","text",[43,44,40],"code",{"__ignoreMap":45},"",[47,48,50],"h2",{"id":49},"understanding-nextjs-supabase-clients","Understanding Next.js Supabase Clients",[13,52,53],{},"Next.js App Router requires different Supabase clients for different contexts:",[55,56,57,73],"table",{},[58,59,60],"thead",{},[61,62,63,67,70],"tr",{},[64,65,66],"th",{},"Context",[64,68,69],{},"Supabase Client",[64,71,72],{},"Use Case",[74,75,76,88,99,109],"tbody",{},[61,77,78,82,85],{},[79,80,81],"td",{},"Client Components",[79,83,84],{},"createBrowserClient",[79,86,87],{},"Browser-side data fetching",[61,89,90,93,96],{},[79,91,92],{},"Server Components",[79,94,95],{},"createServerClient (cookies)",[79,97,98],{},"SSR data fetching",[61,100,101,104,106],{},[79,102,103],{},"Server Actions",[79,105,95],{},[79,107,108],{},"Form submissions, mutations",[61,110,111,114,117],{},[79,112,113],{},"Middleware",[79,115,116],{},"createMiddlewareClient",[79,118,119],{},"Auth refresh, redirects",[47,121,123],{"id":122},"part-1-setting-up-supabase-clients-nextjs-supabase","Part 1: Setting Up Supabase Clients Next.js Supabase",[31,125,127],{"id":126},"browser-client-nextjs","Browser Client Next.js",[129,130,132],"code-block",{"label":131},"lib/supabase/client.ts",[36,133,136],{"className":134,"code":135,"language":41},[39],"import { createBrowserClient } from '@supabase/ssr'\n\nexport function createClient() {\n  return createBrowserClient(\n    process.env.NEXT_PUBLIC_SUPABASE_URL!,\n    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!\n  )\n}\n",[43,137,135],{"__ignoreMap":45},[31,139,141],{"id":140},"server-client-nextjs","Server Client Next.js",[129,143,145],{"label":144},"lib/supabase/server.ts",[36,146,149],{"className":147,"code":148,"language":41},[39],"import { createServerClient, type CookieOptions } from '@supabase/ssr'\nimport { cookies } from 'next/headers'\n\nexport async function createClient() {\n  const cookieStore = await cookies()\n\n  return createServerClient(\n    process.env.NEXT_PUBLIC_SUPABASE_URL!,\n    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,\n    {\n      cookies: {\n        getAll() {\n          return cookieStore.getAll()\n        },\n        setAll(cookiesToSet) {\n          try {\n            cookiesToSet.forEach(({ name, value, options }) =>\n              cookieStore.set(name, value, options)\n            )\n          } catch {\n            // Called from Server Component, ignore\n          }\n        },\n      },\n    }\n  )\n}\n",[43,150,148],{"__ignoreMap":45},[47,152,154],{"id":153},"part-2-authentication-in-server-actions-nextjs-cursor","Part 2: Authentication in Server Actions Next.js Cursor",[31,156,158],{"id":157},"always-verify-authentication-nextjs-supabase","Always Verify Authentication Next.js Supabase",[13,160,161],{},"AI-generated Server Actions often miss authentication checks:",[129,163,165],{"label":164},"INSECURE: Missing auth check",[36,166,169],{"className":167,"code":168,"language":41},[39],"// app/actions.ts - DANGEROUS\n'use server'\n\nexport async function updateProfile(formData: FormData) {\n  const supabase = await createClient()\n\n  // Missing auth check!\n  await supabase.from('profiles').update({\n    name: formData.get('name')\n  }).eq('id', formData.get('userId'))\n}\n",[43,170,168],{"__ignoreMap":45},[129,172,174],{"label":173},"SECURE: With auth verification",[36,175,178],{"className":176,"code":177,"language":41},[39],"// app/actions.ts - SECURE\n'use server'\n\nimport { createClient } from '@/lib/supabase/server'\n\nexport async function updateProfile(formData: FormData) {\n  const supabase = await createClient()\n\n  // Verify authentication\n  const { data: { user }, error: authError } = await supabase.auth.getUser()\n\n  if (authError || !user) {\n    throw new Error('Unauthorized')\n  }\n\n  // Only update current user's profile\n  const { error } = await supabase.from('profiles').update({\n    name: formData.get('name')\n  }).eq('id', user.id)  // Use authenticated user's ID\n\n  if (error) {\n    throw new Error('Failed to update profile')\n  }\n\n  return { success: true }\n}\n",[43,179,177],{"__ignoreMap":45},[181,182,183],"warning-box",{},[13,184,185,188,189,192],{},[16,186,187],{},"Critical:"," Never trust user ID from form data. Always get the user ID from ",[43,190,191],{},"auth.getUser()"," to prevent user impersonation.",[47,194,196],{"id":195},"security-checklist","Security Checklist",[198,199,201],"h4",{"id":200},"pre-launch-checklist-for-cursor-nextjs-supabase","Pre-Launch Checklist for Cursor + Next.js + Supabase",[13,203,204],{},"Correct Supabase client for each context",[13,206,207],{},"RLS enabled on all tables",[13,209,210],{},"Auth verification in all Server Actions",[13,212,213],{},"Middleware protects authenticated routes",[13,215,216],{},"Service role key only in server code",[13,218,219],{},"User ID from auth, not from client input",[13,221,222],{},"Environment variables in Vercel",[13,224,225],{},".cursorignore excludes .env files",[227,228,229,233],"stack-comparison",{},[31,230,232],{"id":231},"alternative-stack-configurations","Alternative Stack Configurations",[227,234,235,238],{},[13,236,237],{},"Cursor + Supabase + Vercel\nGeneral Cursor + Supabase guide without Next.js-specific patterns. Framework-agnostic approach.",[36,239,242],{"className":240,"code":241,"language":41},[39],"      Next.js + Supabase + Vercel\n      Framework-focused guide without Cursor-specific considerations.\n\n\n      Cursor + Next.js + Prisma\n      Swap Supabase for Prisma ORM. Different security model with type-safe queries.\n",[43,243,241],{"__ignoreMap":45},[245,246,247,254,260],"faq-section",{},[248,249,251],"faq-item",{"question":250},"Why do I need different Supabase clients?",[13,252,253],{},"Next.js App Router runs code in different contexts (browser, server, edge). Each context handles cookies and authentication differently. Using the wrong client causes auth state mismatches or security vulnerabilities.",[248,255,257],{"question":256},"Can I use getSession() instead of getUser()?",[13,258,259],{},"For security-critical operations, use getUser() as it verifies the JWT with Supabase's servers. getSession() only checks the local JWT and could be spoofed. For read-only UI decisions, getSession() is acceptable.",[248,261,263],{"question":262},"Do I need middleware if I have RLS?",[13,264,265],{},"Yes. RLS protects your database, but middleware protects your UI. Without middleware, unauthenticated users can see protected pages (even if the data is empty due to RLS). Both layers are important.",[267,268,269,275,280],"related-articles",{},[270,271],"related-card",{"description":272,"href":273,"title":274},"Framework-focused guide","/blog/blueprints/nextjs-supabase-vercel","Next.js + Supabase + Vercel",[270,276],{"description":277,"href":278,"title":279},"General Cursor stack","/blog/blueprints/cursor-supabase-vercel","Cursor + Supabase + Vercel",[270,281],{"description":282,"href":283,"title":284},"Deep dive into Supabase","/blog/guides/supabase","Supabase Security Guide",[286,287,290,294],"cta-box",{"href":288,"label":289},"/","Start Free Scan",[47,291,293],{"id":292},"building-with-nextjs-and-supabase","Building with Next.js and Supabase?",[13,295,296],{},"Scan your app for authentication and RLS issues.",{"title":45,"searchDepth":298,"depth":298,"links":299},2,[300,302,303,307,310,313],{"id":33,"depth":301,"text":34},3,{"id":49,"depth":298,"text":50},{"id":122,"depth":298,"text":123,"children":304},[305,306],{"id":126,"depth":301,"text":127},{"id":140,"depth":301,"text":141},{"id":153,"depth":298,"text":154,"children":308},[309],{"id":157,"depth":301,"text":158},{"id":195,"depth":298,"text":196,"children":311},[312],{"id":231,"depth":301,"text":232},{"id":292,"depth":298,"text":293},"blueprints","2026-01-30","2026-02-26","Security guide for Cursor + Next.js + Supabase stack. Configure RLS, secure Server Components, protect API routes, and handle authentication properly.",false,"md",null,"purple",{},true,"Complete security configuration for Next.js apps with Supabase built in Cursor.","/blog/blueprints/cursor-nextjs-supabase","12 min read","[object Object]","Article",{"title":5,"description":317},{"loc":325},"blog/blueprints/cursor-nextjs-supabase",[],"summary_large_image","_mGG_AouPrRvFkmQK_k6NCD2L-ytW7tlhYrvvysP3nc",1775843920179]