Build a Fullstack Trello App with NextJS 15, Supabase, TailwindCSS, Drag & Drop

PedroTechAbout 8 min readJul 23, 2025Watch original
THE SUMMARYAI-generated

Key Concepts

  • Full-Stack Development: Building both the front-end (user interface) and back-end (server-side logic and database) of an application.
  • Trello Clone: Replicating the functionality and design of the Trello project management tool.
  • Next.js: A React framework for building server-rendered and statically generated web applications.
  • TypeScript: A superset of JavaScript that adds static typing.
  • Tailwind CSS: A utility-first CSS framework.
  • Superbase: An open-source Firebase alternative providing database, authentication, and real-time functionalities.
  • React DND (Drag and Drop): A library for implementing drag-and-drop interfaces in React.
  • Shadcn UI: A collection of pre-designed, customizable React components.
  • Radix UI: A set of unstyled, accessible React primitives.
  • Clerk: A platform for user authentication and billing.
  • Stripe: A payment processing platform.
  • CRUD Operations: Create, Read, Update, and Delete operations on data.
  • RLS (Row Level Security): A Superbase feature to control data access at the row level.
  • OAUTH: An open standard for access delegation, commonly used for authentication.
  • JWT (JSON Web Token): A standard for securely transmitting information as a JSON object.

Project Setup and Initial Configuration

  • Creating a Next.js App: The tutorial begins by creating a new Next.js project using the npx create-next-app command. TypeScript, ESLint, Tailwind CSS, the App Router, and Turbopack are selected during project setup.
  • Installing Dependencies: A comprehensive list of packages is installed using npm install, including:
    • superbase-js: For database interactions.
    • react-dnd, dnd-kit-core, dnd-kit-sortable, @dnd-kit/utilities: For drag-and-drop functionality.
    • @radix-ui/react-dialog, @radix-ui/react-label, @radix-ui/react-select, @radix-ui/react-slot: Radix UI components.
    • lucide-react: For icons.
    • class-variance-authority: For compatibility with Radix UI.
    • tailwind-merge, clsx: For managing Tailwind CSS class names.
    • @clerk/nextjs: For authentication and billing.
    • tailwindcss-animate: For Tailwind CSS animations.
  • Shadcn UI Setup: Shadcn UI is initialized using npx shadcn-ui@latest init. The neutral color is chosen as the base color. Components like Button, Card, Input, Label, Textarea, Dialog, Select, and Badge are added using npx shadcn-ui@latest add.
  • Environment Variables: Clerk API keys (public publishable key and secret key) and Superbase credentials (URL and anonymous key) are stored in a .env file.

Navbar Component

  • Creating the Navbar: A Navbar component is created as a client component (navbar.tsx).
  • Basic Structure: The navbar includes a logo (Trello icon from Lucid React), the website name ("Trello clone"), and links for sign-in and sign-up.
  • Styling: Tailwind CSS classes are used to style the navbar, including borders, background opacity, backdrop blur, sticky positioning, and responsive padding.
  • Conditional Rendering: The navbar content changes based on user authentication status. If the user is signed in, it displays a welcome message with the user's name and a link to the dashboard. If not, it shows sign-in and sign-up buttons.
  • Clerk Integration: The useUser hook from Clerk is used to determine the user's authentication status and retrieve user information.

Authentication with Clerk

  • Clerk Setup: A new application is created in Clerk, named "Trello clone app." Email/password and GitHub sign-up methods are enabled.
  • Middleware Configuration: A middleware.ts file is created to handle authentication middleware using ClerkMiddleware from @clerk/nextjs/server.
  • Clerk Provider: The ClerkProvider component is used to wrap the entire application in the root layout (app/layout.tsx), providing access to Clerk's functionalities throughout the project.
  • OAUTH API Keys: The tutorial mentions that while Clerk uses shared pre-configured credentials for development, production deployments require obtaining your own API keys for OAUTH providers like Google or GitHub.

Superbase Database Setup

  • Superbase Project Creation: A new project is created in Superbase, including setting a database password and choosing a region.
  • Table Creation: Three tables are created in Superbase:
    • Boards: Stores information about each board (ID, title, description, color, user ID, created at, updated at).
    • Columns: Stores information about columns within a board (ID, board ID, title, sort order, created at). A foreign key relationship is established with the Boards table, with cascading delete behavior.
    • Tasks: Stores information about tasks within a column (ID, column ID, title, description, assignee, due date, priority, sort order, created at). A foreign key relationship is established with the Columns table, with cascading delete behavior.
  • Data Types: Specific data types are chosen for each column, such as text, date, int4, and timestamp.
  • RLS Policies: Row Level Security (RLS) policies are created for each table to restrict data access based on user authentication. Policies are defined for SELECT, INSERT, UPDATE, and DELETE operations. The requesting_user_id() function is used to securely identify the authenticated user.
  • Clerk Superbase Integration: The tutorial explains how to integrate Clerk with Superbase by enabling the Superbase integration in Clerk and adding the Clerk domain to Superbase's third-party OAUTH providers. It also details the necessary changes to the Superbase client creation and RLS policies to work with Clerk's authentication.

Superbase Client and Services

  • Superbase Models: TypeScript interfaces are created to represent the structure of the database tables (Board, Column, Task) in lib/superbase/superbase-models.ts.
  • Superbase Client Setup: Two files are created for Superbase client initialization:
    • lib/superbase/client.ts: For client-side components, using createBrowserClient from @superbase/superbase-js.
    • lib/superbase/server.ts: For server-side components, using createServerClient from @superbase/superbase-js and the cookies function from next/headers.
  • Board Service: A BoardService object is created in lib/services.ts to encapsulate CRUD operations for the Boards table. It includes functions for:
    • getBoards(userId: string): Retrieves all boards for a specific user.
    • createBoard(board: Omit<Board, 'id' | 'created_at' | 'updated_at'>): Creates a new board.
    • getBoard(boardId: string): Retrieves a specific board by ID.
    • updateBoard(boardId: string, updates: Partial<Board>): Updates an existing board.
  • Column Service: A ColumnService object is created in lib/services.ts to encapsulate CRUD operations for the Columns table. It includes functions for:
    • createColumn(column: Omit<Column, 'id' | 'created_at'>): Creates a new column.
    • getColumns(boardId: string): Retrieves all columns for a specific board.
  • Task Service: A TaskService object is created in lib/services.ts to encapsulate CRUD operations for the Tasks table. It includes functions for:
    • createTask(task: Omit<Task, 'id' | 'created_at'>): Creates a new task.
    • getTasksByBoard(boardId: string): Retrieves all tasks for a specific board.
    • moveTask(taskId: string, newColumnId: string, newOrder: number): Moves a task to a different column.
  • Board Data Service: A BoardDataService object is created in lib/services.ts to handle operations that involve multiple services. It includes a function for:
    • createBoardWithDefaultColumns(boardData: { title: string; description?: string | null; color?: string | null; }, userId: string): Creates a new board with default columns (To Do, In Progress, Review, Done).

Dashboard Page Implementation

  • Dashboard Page Structure: The DashboardPage component (app/dashboard/page.tsx) is created as a client component. It includes a welcome section, statistics about the boards, and a section to display the boards.
  • Use Boards Hook: A useBoards hook is created in lib/hooks/use-boards.ts to manage the list of boards, loading state, errors, and functions to alter the boards. It uses the useState hook to manage the state and the useEffect hook to load the boards when the component mounts.
  • Use Board Hook: A useBoard hook is created in lib/hooks/use-boards.ts to manage a single board.
  • Board Display: The boards are displayed in a grid or list format, depending on the selected view mode. Each board is rendered as a link to the individual board page.
  • Create Board Functionality: A button is added to allow users to create new boards. The handleCreateBoard function is called when the button is clicked, which calls the createBoardWithDefaultColumns function from the BoardDataService.
  • Loading and Error Handling: The component displays a loading indicator while the boards are being fetched and an error message if there is an error.

Board Page Implementation

  • Board Page Structure: The BoardPage component (app/boards/[id]/page.tsx) is created as a client component. It includes the navbar and a section to display the board columns.
  • Use Params Hook: The useParams hook from next/navigation is used to get the board ID from the URL.
  • Column Display: The columns are displayed using a DroppableColumn component, which is a wrapper component that handles the drag-and-drop functionality.
  • Task Display: The tasks within each column are displayed using a SortableTask component, which is a wrapper component that handles the drag-and-drop functionality.
  • Drag and Drop Implementation: The DndContext component from dnd-kit-core is used to wrap the entire board content, providing the necessary context for drag-and-drop operations. The useDroppable and useSortable hooks from dnd-kit-core and dnd-kit-sortable are used to implement the drag-and-drop functionality for the columns and tasks.
  • Drag and Drop Functions: The handleDragStart, handleDragOver, and handleDragEnd functions are created to handle the drag-and-drop events. These functions update the UI and the database to reflect the new order of the columns and tasks.

Billing and Payment with Clerk

  • Clerk Billing Setup: Billing is enabled in the Clerk dashboard, and three plans are created: Free, Pro, and Enterprise.
  • Plan Context: A PlanContext is created in lib/contexts/plan-context.tsx to provide access to the user's plan information throughout the application.
  • Dashboard Layout: A DashboardLayout component (app/dashboard/layout.tsx) is created as a server component to fetch the user's plan information using the Clerk OAUTH functions and pass it to the PlanContext.
  • Conditional Rendering: The UI is updated based on the user's plan. For example, the "Create Board" button is disabled for free users who have already created one board.
  • Upgrade Dialogue: A dialogue is displayed to free users who have reached their board limit, prompting them to upgrade to a paid plan.
  • Pricing Page: A PricingPage component (app/pricing/page.tsx) is created to display the available plans using the PricingTable component from @clerk/nextjs.
  • Subscription Management: Users can manage their subscription through their Clerk account settings.

Conclusion

The tutorial provides a detailed, step-by-step guide to building a full-stack Trello clone using Next.js, TypeScript, Tailwind CSS, Superbase, React DND, Shadcn UI, and Clerk. It covers a wide range of topics, including project setup, database design, authentication, drag-and-drop implementation, and billing. The tutorial emphasizes best practices, such as using TypeScript for type safety, creating reusable components, and encapsulating database logic in services. While the project is complex, the tutorial breaks it down into manageable steps and provides clear explanations of the code. The final result is a functional Trello clone with a professional-looking design and robust features.

AI summaries can miss context or contain errors. Check important details against the original video.

Go a little deeper.

Have a question about this video? Load its transcript to open the video chat.