Skip to content

Supabase + Next.js Notes App#1387

Open
shujanislam wants to merge 10 commits intovercel:mainfrom
shujanislam:main
Open

Supabase + Next.js Notes App#1387
shujanislam wants to merge 10 commits intovercel:mainfrom
shujanislam:main

Conversation

@shujanislam
Copy link

@shujanislam shujanislam commented Jan 23, 2026

Description

This PR refines the supabase-nextjs example into a focused notes web app that demonstrates how to insert and retrieve data from a Supabase (Postgres) database using the Next.js App Router.

Screenshot from 2026-01-23 21-10-19

Key changes:

  • Implemented a simple notes UI that reads data on the server using app/queries.ts and renders it in app/page.tsx via SSR.
  • Added a CreateNotes client component that uses a server action in app/action.ts to insert new notes into Supabase.
  • Improved UX for creating notes:
    • Popup form anchored to the “Create Note” button that no longer shifts the layout of the note cards.
    • Form auto-resets and closes on successful submission.
    • Inline error message and loading state when the server action fails or is pending.
  • Styled the notes list and create form with a modern Next.js-style dark UI that integrates with @vercel/examples-ui.
  • Documented the example’s structure and Supabase integration in README.md, including:
    • Where mutation/query logic lives (app/action.ts, app/queries.ts, lib/supabase/).
    • Required environment variables for Supabase.
    • Clear local development steps (pnpm install, .env.local, pnpm dev).
      This makes the example more realistic while clearly showcasing the recommended patterns for Supabase + Next.js (App Router, SSR, Server Actions).

Type of Change

  • New Example
  • Example updates (Bug fixes, new features, etc.)
  • Other (changes to the codebase, but not to examples)

New Example Checklist

  • 🛫 npm run new-example was used to create the example
  • 📚 The template wasn't used but I carefuly read the Adding a new example steps and implemented them in the example
  • 📱 Is it responsive? Are mobile and tablets considered?

Copilot AI review requested due to automatic review settings January 23, 2026 15:46
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR transforms the supabase-nextjs example into a focused notes web application that demonstrates how to insert and retrieve data from a Supabase (Postgres) database using Next.js App Router with server-side rendering and Server Actions.

Changes:

  • Implemented a notes CRUD interface with server-side data fetching and Server Actions for mutations
  • Added client components for creating notes with form validation, loading states, and error handling
  • Configured the project with Tailwind CSS, TypeScript, and Turborepo for a modern development experience

Reviewed changes

Copilot reviewed 17 out of 19 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
package.json Defines project dependencies and build scripts
vercel.json, turbo.json Vercel deployment and Turborepo configuration
tsconfig.json TypeScript compiler configuration
tailwind.config.js, postcss.config.js Tailwind CSS setup
lib/supabase/server.ts, client.ts Supabase client initialization for server and browser
app/action.ts Server Action for creating notes
app/queries.ts Server-side query function for fetching notes
app/page.tsx Main page component with SSR
app/layout.tsx Root layout with metadata
components/CreateNotes.tsx Client component for note creation form
components/NotesCard.tsx Presentational component for displaying notes
README.md Documentation with setup instructions
.gitignore, .eslintrc.json Project configuration files

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 60 to 83
<input
name="username"
type="text"
className="h-8 rounded-md border border-zinc-800 bg-zinc-950 px-2 text-xs text-zinc-100 shadow-inner outline-none focus:border-zinc-500 focus:ring-1 focus:ring-zinc-500"
/>
</label>
<label className="flex flex-col gap-1">
<span className="text-[11px] font-medium text-zinc-300">
Title
</span>
<input
name="title"
type="text"
className="h-8 rounded-md border border-zinc-800 bg-zinc-950 px-2 text-xs text-zinc-100 shadow-inner outline-none focus:border-zinc-500 focus:ring-1 focus:ring-zinc-500"
/>
</label>
<label className="flex flex-col gap-1">
<span className="text-[11px] font-medium text-zinc-300">
Description
</span>
<textarea
name="description"
className="min-h-[80px] rounded-md border border-zinc-800 bg-zinc-950 px-2 py-1 text-xs text-zinc-100 shadow-inner outline-none focus:border-zinc-500 focus:ring-1 focus:ring-zinc-500"
/>
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Form inputs are missing the required attribute. While validation exists on the server, adding required to the input elements (lines 60, 70, and 80) would provide better UX by triggering native browser validation before submission, preventing unnecessary server requests for empty fields.

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

Comment on lines +9 to +16
To run this example locally you need a `.env.local` file with your Supabase project keys:

```env
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
```

Add your Supabase API keys there and then start the dev server.
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README is missing critical information about setting up the database schema in Supabase. Users need to create the 'notes' table with the required columns (id, username, title, description, created_at) before running the application. Add a section explaining the required database setup, including the SQL schema or instructions for creating the table in the Supabase dashboard.

Copilot uses AI. Check for mistakes.
{
"name": "next"
}
]
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding path aliases to the tsconfig.json for cleaner imports. For example, adding "paths": { "@/*": ["./*"] } would allow imports like import { createSupabaseServer } from '@/lib/supabase/server' instead of using relative paths like '../lib/supabase/server'. This is a common Next.js pattern and improves code maintainability.

Suggested change
]
],
"baseUrl": ".",
"paths": {
"@/*": ["./*"]
}

Copilot uses AI. Check for mistakes.
.select('*')
.order('created_at', { ascending: false }) // ascending: false, to show latest notes on top

if (error) throw new Error('Error while finding notes')
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error handling in fetchNotes throws a generic error message "Error while finding notes" which loses the original Supabase error details. Consider throwing the original error or including the Supabase error message to help with debugging: throw new Error(error.message) instead of the generic message.

Suggested change
if (error) throw new Error('Error while finding notes')
if (error) throw new Error(error.message)

Copilot uses AI. Check for mistakes.
"@vercel/examples-ui": "^2.0.1",
"next": "^16.0.10",
"react": "^19.2.1",
"react-dom": "^19.2.1"
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The package.json is missing required Supabase dependencies. The code imports from '@supabase/ssr' in lib/supabase/server.ts and lib/supabase/client.ts, and uses 'server-only' in lib/supabase/server.ts, but these packages are not listed in the dependencies. Add the following to the dependencies section:

  • "@supabase/ssr" (version should be specified, e.g., "^0.1.0" or later)
  • "server-only" (typically "^0.0.1")

Without these dependencies, the application will fail to build and run.

Suggested change
"react-dom": "^19.2.1"
"react-dom": "^19.2.1",
"@supabase/ssr": "^0.1.0",
"server-only": "^0.0.1"

Copilot uses AI. Check for mistakes.
Comment on lines +43 to +44
{open && (
<div className="absolute right-0 top-full z-10 mt-3 w-80 sm:w-96 md:w-[28rem] rounded-xl border border-zinc-800 bg-zinc-950/95 p-4 shadow-xl ring-1 ring-white/10">
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The popup form doesn't close when clicking outside of it, which is a common UX pattern users expect. Consider adding an onClick handler to a backdrop div or using a useEffect with a click-outside listener to close the form when users click outside the popup area.

Copilot uses AI. Check for mistakes.
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tsconfig.json is using "jsx": "react-jsx" but for Next.js projects, this should be "jsx": "preserve" to let Next.js handle the JSX transformation. This is the standard configuration for Next.js App Router projects and ensures proper handling of React JSX.

Suggested change
"jsx": "react-jsx",
"jsx": "preserve",

Copilot uses AI. Check for mistakes.
Comment on lines +21 to +29
const { error } = await supabase.from('notes').insert({
username,
title,
description,
})

if (error) {
throw new Error(error.message)
}
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After successfully inserting a note, the server action should call revalidatePath to refresh the page data so the new note appears immediately. Add the following import at the top: import { revalidatePath } from 'next/cache' and call revalidatePath('/') after the successful insert (line 29, before the catch block ends or within the try block after checking for errors). Without this, users will need to manually refresh the page to see their newly created note.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +24
const supabase = await createSupabaseServer()

const { error } = await supabase.from('notes').insert({
username,
title,
description,
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation only checks if fields are present and are strings, but doesn't validate that they're non-empty or trim whitespace. This allows creating notes with only whitespace or empty strings. Consider adding validation to ensure fields are not empty after trimming, e.g., if (!username.trim() || !title.trim() || !description.trim()) { throw new Error('Fields cannot be empty') }

Suggested change
const supabase = await createSupabaseServer()
const { error } = await supabase.from('notes').insert({
username,
title,
description,
const trimmedUsername = username.trim()
const trimmedTitle = title.trim()
const trimmedDescription = description.trim()
if (!trimmedUsername || !trimmedTitle || !trimmedDescription) {
throw new Error('Fields cannot be empty')
}
const supabase = await createSupabaseServer()
const { error } = await supabase.from('notes').insert({
username: trimmedUsername,
title: trimmedTitle,
description: trimmedDescription,

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,32 @@
import { Page, Text, Code, Link } from '@vercel/examples-ui'
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused imports Code, Link.

Suggested change
import { Page, Text, Code, Link } from '@vercel/examples-ui'
import { Page, Text } from '@vercel/examples-ui'

Copilot uses AI. Check for mistakes.
@vercel
Copy link
Contributor

vercel bot commented Jan 23, 2026

@shujanislam is attempting to deploy a commit to the Vercel Examples Team on Vercel.

A member of the Team first needs to authorize it.

@socket-security
Copy link

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​supabase/​ssr@​0.8.01001008195100

View full report

@vercel
Copy link
Contributor

vercel bot commented Jan 23, 2026

Deployment failed with the following error:

Creating the Deployment Timed Out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant