A modern Next.js 15 starter template with Supabase authentication, React Query for data fetching, and built-in wrappers for queries and authentication. This starter is designed to accelerate development by providing preconfigured hooks, utilities, and best practices.
Create a new project using the CLI (if available):
npx create-next-supabase-starter@latest my-project
Or manually clone the repository:
git clone https://github.com/your-username/your-repo.git my-project
cd my-project
pnpm install
Create a .env.local
file and add:
NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
pnpm dev
Your app should be running at http://localhost:3000.
The AuthContext
ensures user authentication is managed across the app.
"use client";
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export function AuthProvider({ children }: { children: React.ReactNode }) {
const { data: user, isLoading } = useQuery({
queryKey: ["user"],
queryFn: async () => {
const { data } = await supabase.auth.getUser();
return data?.user ?? null; // ā
Ensures it's never undefined
},
staleTime: 0,
});
return (
<AuthContext.Provider value={{ user: user ?? null, loading: isLoading }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error("useAuth must be used within an AuthProvider");
}
return context;
}
Use the useClientFetch
hook for fetching data efficiently on client components:
import { useClientFetch } from "@/hooks/useClientFetch";
const Posts = () => {
const { data, isLoading } = useClientFetch("posts", "posts");
if (isLoading) return <p>Loading...</p>;
return (
<ul>
{data?.map((post) => (
<li key={post.id}>{post.name}</li>
))}
</ul>
);
};
const FilteredUsers = () => {
const { data, isLoading } = useClientFetch(
"filtered-users", // key
"users", // table name
5000, // cache time
(query) => query.eq("role", "admin") // Supabase query filter
);
if (isLoading) return <p>Loading...</p>;
return (
<ul>
{data?.map((user) => (
<li key={user.id}>
{user.name} ({user.role})
</li>
))}
</ul>
);
};
Use the useClientMutate
hook for inserting, updating, and deleting data on client components:
import { useClientMutate } from "@/hooks/useClientMutate";
const AddPost = () => {
const mutation = useClientMutate("posts", "insert");
const handleSubmit = async () => {
mutation.mutate({ id: Date.now(), name: "New Post" });
};
return <button onClick={handleSubmit}>Add Post</button>;
};
const UpdatePost = () => {
const mutation = useClientMutate("posts", "update");
const handleUpdate = () => {
mutation.mutate({ id: 1, name: "Updated Post" });
};
return <button onClick={handleUpdate}>Update User</button>;
};
const DeleteUser = () => {
const mutation = useClientMutate("users", "delete");
const handleDelete = () => {
mutation.mutate({ id: 1 });
};
return <button onClick={handleDelete}>Delete User</button>;
};
š¦ my-project
āāā š app # Next.js app directory
ā āāā š (auth) # Authentication pages
ā ā āāā š auth # Authentication utilities
ā ā ā āāā š confirm # Confirmation route
ā ā ā ā āāā route.ts
ā ā āāā š error # Error handling
ā ā āāā š login # Login page
ā ā āāā š register # Register page
ā ā āāā actions.ts # Auth actions
ā ā āāā layout.tsx # Auth layout
ā āāā š (dashboard) # Dashboard pages
ā āāā favicon.ico # Favicon
ā āāā globals.css # Global styles
ā āāā layout.tsx # Main layout
ā āāā not-found.tsx # 404 Page
ā āāā page.tsx # Home page
āāā š components # Shared UI components
āāā š hooks # Custom React Query hooks
ā āāā use-client-fetch.ts
ā āāā use-client-mutation.ts
āāā š lib # Utilities & helpers
āāā š public # Static assets
āāā š supabase # Supabase integrations clients
ā āāā client.ts # Supabase client
ā āāā middleware.ts # Middleware configuration
ā āāā server.ts # Server-side Supabase utilities
āāā š node_modules # Dependencies
āāā .env # Environment configuration
āāā .env.example # Example environment variables
āāā .gitignore # Git ignore file
āāā components.json # UI component configurations
āāā eslint.config.mjs # ESLint configuration
āāā middleware.ts # Global middleware
āāā next-env.d.ts # Next.js environment types
āāā next.config.ts # Next.js configuration
āāā package.json # Project dependencies
āāā pnpm-lock.yaml # Lock file
āāā postcss.config.mjs # PostCSS configuration
āāā README.md # Project documentation
āāā tailwind.config.ts # Tailwind CSS configuration
āāā tsconfig.json # TypeScript configuration