
Build a real-world full-stack app with Next.js using TypeScript, Tailwind, Prisma, and BetterAuth. Explore authentication, real-time presence, chat, image uploads with Cloudinary, and admin moderation.
Set up your development environment for building a full-stack Next.js app by choosing a code editor, installing Node.js (version 20.9+), and configuring tools across Windows, Mac, or Linux.
Access course assets and source code for this Next.js full-stack course by downloading the assets zip via the resources button and exploring the GitHub demo repo.
Stay calm when stuck, solve problems by fixing mistakes, restart the app if needed, use Google and AI to diagnose issues, compare versions, and use Q&A for detailed help.
Choose your start point wisely: jump into Next.js if you know React and its hooks, or begin with Appendix A to learn React basics and a simple create-read-update-delete operation.
Discover how Next.js enhances React apps with server-side rendering, routing, and built-in optimizations, blending fast load times with interactive hydration for search engine optimization.
Create a Next.js project with npx create-next-app, enable TypeScript, ESLint, React compiler, Tailwind CSS, and app router in a source directory, then run npm run dev to view at localhost:3000.
Take a whistle-stop tour of the Next.js project, including VS Code setup, Tailwind and extensions, and key folders like .next, node_modules, public, and source with page.tsx and layout.tsx.
Install and configure the Hero UI component library built on Tailwind and React ARIA to create accessible, styled buttons with icons using Hero UI styles and React icons.
Explore how Next.js handles routing with the app folder, creating pages like home and members, using page.tsx, next/link, and nested layouts for seamless client-side navigation.
Create a fixed, full-width top navbar in a Next.js app by building a reusable navbar.tsx with links to home, members, lists, and messages, styled with Tailwind and a gradient.
Expand routing in a Next.js app by adding lists and messages pages, configuring login and register routes, using parentheses to ignore folder names, and updating navbar to highlight active routes.
Learn to highlight active nav links in a Next.js app by creating a client NavLink that uses usePathName to compare the current path with each href.
Save your code in source control with Git and publish to GitHub, using VS Code to stage and commit changes, create repositories, and handle authentication.
Built a Next.js app, integrated Next.UI and Tailwind CSS, and explored routing with page.tsx. Committed changes to source control to create backups and track history, with authentication upcoming.
Explore authentication in section 3 by building login and register forms with React Hook Form, using BetterAuth for secure auth, and storing users via Prisma ORM in a Next.js app.
Construct a centered login form using Hero UI card and inputs, style it for clarity, and set the login page as a server component with a client-side form.
Learn how to build a login form in React with controlled and uncontrolled inputs, using useState, onChange, and handleSubmit, prevent default, in a Next.js context.
Learn how to build forms in React using React Hook Form, replacing controlled inputs with register and handleSubmit, and apply schema-based validation with Zod and resolvers.
Validate a login form using zod schema validation and a react-hook-form resolver, with email and password rules and a login schema. Improve accessibility with hero ui text fields and errors.
Create a register form by cloning the login form, add a name field and a confirm password using zod refinement, and wire validation messages for signup.
Explore how BetterAuth streamlines authentication for a Next.js app, using session cookies, sign-in and sign-out, and easy third-party logins. Learn the database session storage approach with Prisma and password hashing.
Explore Prisma ORM, an object-relational mapper that translates code into database queries and offers type-safe access via models and the Prisma client. Focus on Postgres deployment, migrations, and Prisma Studio.
Install and configure BetterAuth to power user login and registration, using env vars, a secret key, and a database-backed session store with Prisma, following the step-by-step docs.
Install Prisma and PostgreSQL tooling for the BetterAuth configuration, initialize Prisma, and configure a development PostgreSQL database with a Prisma client for the app.
Configure BetterAuth with Prisma and PostgreSQL in a Next.js app, update the Prisma schema, and enable email and password authentication with API routes and a client.
Register a new user with BetterAuth by signing up through the form, passing email, password, and name to the authClient, and redirecting to /members on success.
Sign in a user with BetterAuth by submitting an async login form using email and password, and redirect to /members on success. Handle onError and show toasts for failed logins.
Fetch the current user from a cookie-based session on the server with getCurrentUser in a Next.js app, then render session.user on the members page and persist sign-in.
Add a top-right user menu with an avatar as a dropdown, replacing login buttons for signed-in users, and implement sign-out with next.js router refresh to update the UI.
Protect routes in a Next.js 16 app using the proxy middleware and HTTP-only session cookies. Differentiate public and auth routes, redirect to login when needed, and apply optimistic root protection.
Explore an optional lesson showing how to run postgres locally on your dev machine with docker and docker-compose, including ports and volumes for persistent data.
Review how section three introduces authentication with React Hook Form, Zod Validation, and BetterAuth. Explore the database focus on Prisma ORM, middleware in Next.js 16, and upcoming section four.
Design the app's user interface, update the Prisma schema, and seed data to power the interface, then fetch data with server actions and understand loading in Next.js.
Extend the Prisma schema with a member model linked to user and a photos table, duplicating name and image for efficient lists, plus cascade delete behavior.
Seed the database by importing member data, creating user accounts, and populating the members and photos tables with Prisma, using a seed.ts runner and Prisma db seed.
Create a grid of clickable member cards in a Next.js app, wiring a member card component to the Prisma-generated member type, Next.js image, and responsive Tailwind styling.
Fix styling by removing card padding. Add a six-gap grid, enable eager image loading, and use date-fns to calculate age from dateOfBirth, then route to a member detail page (404).
Configure dynamic routes in Next.js using a [userID] parameter to render a member detail page, fetch the member by user ID with Prisma, and render server-side with a consistent layout.
Build a two-column member detail page in Next.js, with a left sidebar and right content area, using a reusable layout, async data fetching by user id, and cards.
Create an internal navigation bar for a member detail page in a Next.js app, routing profile, photos, and chats by user id, highlighting the active segment.
Derive active section titles from the url and build a section title component within a Next.js member nav, using a cache function to de-duplicate getMemberByUserId calls.
Learn how Next.js 16 conventions handle uncaught exceptions with custom error pages, using error.tsx at the app root to create an error boundary and present end-user friendly messages.
Update prisma schema to model user, member, and photos relationships, seed data, build UI, fetch data with server actions in Next.js, use convention-based loading, and prepare for a like feature.
Implement a many-to-many like feature by creating a likes join table with source and target user IDs and configuring Prisma models to name the relationships.
Update the prisma schema to model likes as a like table with source and target users, cascade deletes, and a composite key, then push changes and verify with Prisma Studio.
Implement server actions to toggle likes for a member, enforcing authentication with requireAuthUser, and use Prisma to delete or create likes and fetch current user like IDs for display.
Create a client-side like button in a Next.js app to call a server action, manage pending states with use transition, and prevent routing while updating the like status.
Add a server action to fetch target, source, and mutual likes, and display them as cards in a Next.js full-stack app.
Learn to implement a client-side tabbed interface in a Next.js app that filters liked member lists by type (target, source, mutual) via query parameters and live fetch.
In a Next.js app, map tabs to panels and render a grid of member cards. Handle routing and query strings with search params and next/navigation.
Add a loading indicator for tab transitions in a Next.js app using isPending and a spinner, with URL search params updating on router replace.
Build a dynamic user profile section with editable profiles, image uploads, and a profile form for the current user, while hiding chat and updating navigation from the user menu.
Build a profile edit form with a zod schema to validate name, description, city, and country. Pre-populate fields from the member data and log updates on submit.
Add a server action to update a user profile, perform server-side validation with zod, update prisma records, and revalidate the cache to reflect changes.
Learn to handle server-side form errors by returning a discriminated action result object (success or error) with Zod issue arrays, replacing thrown exceptions for robust user feedback.
Handle server action errors by checking the update profile result, show a success toast on success, and surface Zod validation errors on fields or a toast for other errors.
Display user images by loading member photos from the database, render them in a five-column grid with next/image, and overlay buttons to set a main image or delete photos.
Overlay main image and delete buttons on photos with star and delete components. Show controls only on the current user’s profile while preparing future image storage and upload.
Choose cloud storage with Cloudinary for image hosting, avoiding database storage; enable direct browser uploads via signed requests and save the image url and public id.
Set up Cloudinary for image storage with a free account, including 25 monthly transformations, 25 gb storage, and 25 gb bandwidth, plus env vars.
Learn to implement image uploads in a Next.js app using Next Cloudinary's upload button, signing images via a backend endpoint and configuring max files and a Cloudinary folder.
Learn how to store uploaded Cloudinary images in the database with a server action, update the member's photos via Prisma, and trigger revalidation to refresh the member detail page.
Explore using the Cloudinary cld image component in a Next.js app to display Cloudinary images with transformations—width, height, crop, gravity (face)—and fall back to Next.js image when needed.
Implement set main image by updating user and member records via a server action with path revalidation. Then move user interface to a client component and use useTransition for loading.
Implement delete image functionality that removes the image from Cloudinary and the database, updates the UI with cache revalidation, and prevents deleting the main image by disabling the delete button.
Add a transform image function to apply Cloudinary transformations by injecting parameters like c_fill, w, h, g_face, and quality into image URLs, returning non-cloudinary URLs unchanged.
Update resources and upload images with Cloudinary, edit user info, and apply image transformations using server actions for backend functionality. Enable user chat and messaging features.
Set up the messaging feature in section 7 by creating a many-to-many structure that lets users send and receive messages, mirroring the like feature.
Define a prisma message model enabling messages between users with sender and recipient relations, read and delete flags, and set-null on delete, then push and verify with prisma studio.
Build a bottom-aligned chat form in a Next.js full-stack app, validate a message with a minimum length of one using a zod schema, and display messages above with overflow scrolling.
Implement a server action to save chat messages in the database, validate input with a chat schema, and revalidate the recipient's messages route for real time communication.
Use getMessageThread to retrieve the message thread via prisma, filtering by user and recipient, ordering by created, and including sender and recipient details for the user interface.
Create a message data transfer object to shape chat data, map Prisma results to the dto, and include sender and recipient details with formatted dates for a Next.js full-stack app.
Create a chat interface by building a message box component that renders avatars, sender and recipient messages, and read status with conditional styling using clsx in Next.js.
Learn to display chat messages in a Next.js app by rendering a message list and building a reusable message box with sender detection and avatar styling.
Fetch inbox and outbox messages via a container query string, implement a reusable get messages by container with Prisma, map to a message DTO, and render on the page.
Set up the messages layout with a left inbox/outbox navigation and a right content area, including a section title and a message nav for easy switching.
Develop a client-side messages table in a Next.js app to display inbox or outbox messages using hero UI, with clickable rows routing to chats and a delete action.
Implement mark-as-read for inbox messages by updating unread items with Prisma updateMany when a chat opens, and show unread messages in bold while sorting by newest.
Implement a delete message feature that marks messages as deleted for the sender or recipient, deletes only when both sides flag, and updates caches and retrieval logic.
Master robust error handling in a Next.js full-stack app by building a reusable Prisma error handler and using toast notifications for message operations.
Wraps up section 7 by introducing the messaging feature and a join message table to support many-to-many messaging, including date sent, read status, and content, with real-time features coming next.
Implement real-time presence, chat, and notifications in a Next.js app using pusher and WebSockets while noting edge runtime constraints and available alternatives for higher concurrency.
Learn how to enable real-time chat and presence in a Next.js full-stack app using Pusher, including cloud setup, API keys, environment variables, and server-client integration.
Build live chat in a Next.js app using pusher by creating a chat channel from user IDs, sending messages as a dto, and subscribing to channels for real-time delivery.
Enable live chat on the client side by introducing a dedicated messageList component that subscribes to a pusher channel, manages initial messages with useState, and updates in real time.
Learn to implement real-time message read receipts in a Next.js chat app using Pusher, updating read flags on both server and client as users view conversations.
Enable presence in the app by authenticating users for presence channels, configuring a presence dash channel, and implementing a Pusher auth endpoint to manage socket id and user data.
Explore building a global presence store with Zustand in a Next.js app, tracking online members via Pusher events, and implementing a usePresenceStore hook with add, remove, and set methods.
Explore building a usePresence hook in a Next.js app to connect to pusher, subscribe to a presence-nm channel, and update the Zestand store with member add and remove events.
Learn how to wire Redux DevTools to a zustand presence store in a Next.js app, visualize live state with Chrome DevTools, and label actions for online user tracking.
Create a presence component in a Next.js app that reads from a presence store to mark members online. Display presence dots on member cards and avatars with client components.
Create a presence-based avatar component that reads presence from a global store, shows an active status badge, and integrates with the messages UI to trigger new message toasts.
Set up and connect a private Pusher channel for authenticated users, enabling toast notifications for new messages outside chats and inbox updates inside chats, while building a useNotifications hook.
Set up a Zestand message store in VS Code with useMessageStore to manage messages via add, remove, and set operations, enabling real-time updates through Pusher channels.
Wire the message store to the user interface with a notifications hook, updating the message table and showing toasts for new messages while handling inbox and outbox paths.
Enhance the toast notifications by building a clickable message toast that shows the sender's image and name, links to the chat with that user, and uses a five-second accent timeout.
Introduce an unread message count in the message store, initialize to zero, use updateUnreadCount, and fetch the initial count from the database on app load to sync inbox and chat.
Update the user interface to display unread message counts with badges in the MessageNav and the nav bar, and ensure dates render from UTC to ISO strings.
Implement user typing indicators with Pusher client events on private channels, including enabling client events, channel authorization, triggering typing events, and a three-second timeout for real-time notifications.
Learn to implement a user is typing indicator above the chat with an absolute positioned hero ui chip, using isTyping events and the other user’s name.
Implement real-time notifications for likes in a Next.js full-stack app, rendering a clickable toast with the liker's image that links to the profile page.
Learn to implement real-time like notifications with pusher in a Next.js full-stack app, sending toasts on likes via a private channel and managing useEffect bindings for reliable updates.
End section 8 by enabling real-time communication with Pusher, including presence, chat, and notifications, while exploring Sochetti as a cheaper, plug-and-play alternative and preparing to implement pagination, sorting, and filtering.
Explore Soketi as a self-hosted, Pusher-compatible alternative for real-time features in a Next.js app, set up with Docker and environment variables.
Sort and filter data using order by and where queries, and implement pagination with offset and cursor methods; compare performance and use cases like members lists and chats.
Explore filtering, sorting, and pagination in a full-stack next.js app. Build a filter bar with gender toggles, an age range slider, and a sort select, plus bottom pagination.
Explore adding a bottom-sticky, offset-pagination user interface using a copied pagination component, integrated into the members page with responsive styling, and plan to implement an age-range slider next.
Explore building a Next.js age filter using a slider that updates the url with a query string, triggers server-side data fetch, and displays a loading state.
Create a reusable use filter params hook in a Next.js app to manage filter state with URL query strings, memoize updates, and prepare for persistence with cookies.
Learn how to persist selected filter parameters by storing them in a cookie, read and restore the query string on return, and use router replacement to refresh the user interface.
Add an order by feature in a Next.js app by wiring the filters to the query string, implementing handleOrderBy, and configuring the select to sort by newest or last active.
Create an updateLastActive function that updates the updated property to the current date for a user. Trigger it on presence or login to maintain accurate last active ordering.
Implement a gender filter using query string params, toggling male and female selections with a comma-separated values approach, updating the URL, and rendering primary or secondary button styles.
Display an empty state for members view with 'no results found' and a reset filters button that clears the query string and resets the filter cookie using useFilterParams and router.replace.
Build a reusable pagination component with props for page, items per page, and total items, compute total pages via ceiling, and wrap it in a membersPagination component reading URL params.
Learn how to implement offset pagination part 2 in a full-stack next.js app by configuring page and page size, computing skip and take, and returning items with a total count.
Add page size selection to the offset pagination flow in a next.js app by wiring a set page size function, rendering page size options, and syncing total count and filters.
Implement cursor-based pagination by using created date as the cursor to fetch the next page, enabling scalable, infinite scrolling with a next cursor and limit while avoiding full database scans.
Configure cursor-based pagination in a Next.js full-stack app by adding a resetsMessages function, tracking initNextCursor, and a loadMore workflow that appends unique messages.
Implement a with photo filter toggle to display only users with a photo, using a Hero UI switch and the with_photo=true query string.
Implement a with-photo toggle to filter members by image presence using a boolean and query string, updating the URL on change, defaulting to members with photos.
Explore sorting, filtering, and pagination in the app and how Prisma where clauses power data queries. Evaluate pagination approaches and preview upcoming authentication part two.
Enhance your full-stack app with authentication part 2 by implementing user registration, email verification, forgot password flows, and social logins with Google and GitHub, using NextAuth and Resend email service.
Develop a reusable text input component for Next.js forms using React Hook Form's useController, enabling labeled inputs, type-safe props, and integrated error handling; refactor register form to use it.
Create a multi-part register form as a wizard by collecting user details in part one and profile details in part two, with separate schemas and age validation.
Create a two-step form wizard in a Next.js app, splitting inputs into a user form and a profile form, sharing React Hook Form control and validating with Zod before submit.
Improve form usability by implementing a gender radio group with Hero UI, React Hook Form, and accessible labeling. Style the options with a grid layout, icons, and error handling.
Auto populate city and country fields with browser geolocation and Big Data Cloud's free reverse geocoding API. Each update uses a location button and React Hook Form to set values.
Explore completing the registration functionality by wiring sign up to create user and member data, using a database hook and router refresh to update the UI.
Implement email verification for email and password sign up by sending a tokenized link, verifying the token and email, and enforcing verification before sign-in.
Use Resend as a cloud email service to send verification emails in a Next.js app, configure API keys and environment variables, and test with domain constraints and logs.
Add a verify email component in a Next.js app to process token and callback URL from the query string, manage loading, success, and error states, and redirect accordingly.
Learn to implement forgot password with email tokens, reset links, and a dedicated reset-password flow, including routes and forms for secure password resets.
Explore OAuth 2.0 and OpenID Connect for social logins with NextAuth, using Google and GitHub, and understand the authorization flow, authorization codes, and access tokens.
Explore implementing social login with GitHub and Google using BetterAuth, configure OAuth apps, and manage client IDs and secrets in .env to enable sign-in with third-party providers.
Learn to handle social login by auto-creating a member profile and a profile complete flag, update Prisma, and route users to a complete profile form before access.
Implement a complete profile flow for social login by submitting the profile form, handling server response with toast messages, and routing to the members page upon success.
Configure Google OAuth credentials, consent screen, and test users in a Next.js full-stack app; update env vars and auth.ts, then test the Google login flow.
Register users with a two-step wizard using React Hook Form, verify emails, enable secure password resets with token links, support Google and GitHub logins, and prepare for role-based authentication.
*** Now updated to use NextJS 16 and BetterAuth***
Dive into the world of full-stack development with this comprehensive course designed with beginners in mind. This course covers everything from the fundamentals of Next.js to deploying a full-scale application. Whether you are new to programming or looking to expand your existing skills, this course will guide you through every step of building a robust, database driven application.
Here are some of the things that are covered in this course
Creating a Next.js app
Querying a database using Prisma ORM
Securely authenticating users using BetterAuth
Creating a Messaging/Chat feature
Realtime communication using Pusher.
Email verification / Forgot password functionality
Designing the User interface using NextUI
Styling components with TailwindCSS
Utilising server actions to fetch and update the data in Next.js
Image uploading
Publishing the app to the internet with Vercel
Key features of this course
Comprehensive curriculum: 27 hours of high quality video tutorials, challenges and practical content.
Project based learning: Build a major project to showcase your new skills
Pre-Requisites
Basic knowledge of JavaScript, HTML and CSS is recommended.
Tools you need for this course
In this course all the lessons are demonstrated using Visual Studio Code, a free (and fantastic) cross platform code editor. You can of course use any code editor you like and any Operating system you like... as long as it's Windows, Linux or Mac.
Is this course for you?
This course is very practical, about 90%+ of the lessons will involve you coding along with me on this project. If you are the type of person who gets the most out of learning by doing, then this course is definitely for you.
On this course we will build an example Dating Application. All you will need to get started is a computer with your favourite operating system, and a passion for learning how to build a full featured full-stack app based on Next.js.