{"id":39183,"date":"2025-06-06T10:29:01","date_gmt":"2025-06-06T04:59:01","guid":{"rendered":"https:\/\/mobisoftinfotech.com\/resources\/?p=39183"},"modified":"2025-11-03T18:48:36","modified_gmt":"2025-11-03T13:18:36","slug":"supabase-react-typescript-tutorial","status":"publish","type":"post","link":"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial","title":{"rendered":"Supabase React Tutorial: Creating a Supabase Project with React and TypeScript"},"content":{"rendered":"<p>If you&#8217;re exploring modern backend tools that feel like magic, Supabase should be on your radar. It\u2019s open source, fast to set up, and offers a full suite of features: a database, authentication, storage, and real-time subscriptions all powered by Postgres.&nbsp;<\/p>\n\n\n\n<p>In this tutorial, we\u2019ll walk through building a simple web app using Supabase, React, and TypeScript. The focus here is not on mastering React or TypeScript, but on understanding what Supabase offers and how to use it.<\/p>\n\n\n\n<p>For more advanced frontend integration, you might like to explore<a href=\"https:\/\/mobisoftinfotech.com\/services\/reactjs-development-company?utm_source=blog&amp;utm_campaign=supabase-react-typescript-tutorial_blog\"> ReactJS development services<\/a> that can help you scale production-ready solutions efficiently.<\/p>\n\n\n\n<p>By the end, you\u2019ll have a working app with user authentication, database integration, file storage, and real-time updates.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>What Is Supabase?<\/strong><\/h2>\n\n\n\n<p>At its core, Supabase is an open source alternative to Firebase built on top of PostgreSQL. It includes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Database<\/strong>: Managed Postgres with built in REST and real time APIs.<\/li>\n\n\n\n<li><strong>Authentication<\/strong>: Email\/password, OAuth, magic links.<\/li>\n\n\n\n<li><strong>Storage<\/strong>: Upload and serve files with access control.<\/li>\n\n\n\n<li><strong>Edge Functions<\/strong>: Serverless functions for custom backend logic.<\/li>\n\n\n\n<li><strong>Dashboard<\/strong>: UI for managing everything.<\/li>\n<\/ul>\n\n\n\n<p>Let\u2019s get our hands started.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 1: Set Up Your Supabase Project<\/strong><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Go to<a href=\"https:\/\/supabase.com\"> https:\/\/supabase.com<\/a> and sign in.<\/li>\n\n\n\n<li>Click &#8220;New Project&#8221;.<\/li>\n\n\n\n<li>Give it a name, choose a password, and pick a region.<\/li>\n\n\n\n<li>Wait a moment while your project is created.<br><\/li>\n<\/ol>\n\n\n\n<p>Once it&#8217;s ready, you&#8217;ll see the dashboard. You\u2019ll mostly use the Table Editor, Authentication, and Storage tab as the essential tools for any <a href=\"https:\/\/mobisoftinfotech.com\/resources\/blog\/serverless-database\">serverless database<\/a> with the Supabase project.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/mobisoftinfotech.com\/services\/reactjs-development-company?utm_source=blog&amp;utm_medium=supabase-react-typescript-tutorial-cta1 \"><noscript><img decoding=\"async\" width=\"855\" height=\"363\" src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/reactjs-frontend-expertise.png\" alt=\"Power your frontend with expert ReactJS solutions.\" class=\"wp-image-39201\" title=\"ReactJS Expertise to Power Your Frontend\"><\/noscript><img decoding=\"async\" width=\"855\" height=\"363\" src=\"data:image\/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20855%20363%22%3E%3C%2Fsvg%3E\" alt=\"Power your frontend with expert ReactJS solutions.\" class=\"wp-image-39201 lazyload\" title=\"ReactJS Expertise to Power Your Frontend\" data-src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/reactjs-frontend-expertise.png\"><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 2: Create Tables (Database)<\/strong><\/h3>\n\n\n\n<p>1. &nbsp; Let\u2019s make a first <code>posts<\/code> table for saving the user\u2019s post:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Go to Table Editor &gt; New Table<\/li>\n\n\n\n<li>Name it: posts<\/li>\n\n\n\n<li>For now, disable RLS<\/li>\n\n\n\n<li>Add these columns:<br>\n<ol class=\"wp-block-list\">\n<li>id \u2013 UUID, Primary Key (default)<\/li>\n\n\n\n<li>title \u2013 Text<\/li>\n\n\n\n<li>content \u2013 Text<\/li>\n\n\n\n<li>user_id \u2013 UUID (foreign key to auth.users)<\/li>\n\n\n\n<li>created_at \u2013 Timestamp (default: now())<\/li>\n\n\n\n<li>image_url \u2013 Text<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li>Click Save.<\/li>\n<\/ol>\n\n\n\n<p>2. Now let\u2019s make a second <code>user_followers<\/code> table for saving the user\u2019s followers, but this time using SQL Editor:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Go to SQL Editor<\/li>\n\n\n\n<li>Paste the following code for creating a user_followers table with unique constraints to prevent duplication.<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">create table user_followers (\n\n  id uuid primary key <span class=\"hljs-keyword\">default<\/span> gen_random_uuid(),\n\n  user_id uuid references auth.users(id) on <span class=\"hljs-keyword\">delete<\/span> cascade,\n\n  following_id uuid references auth.users(id) on <span class=\"hljs-keyword\">delete<\/span> cascade,\n\n  created_at timestamp <span class=\"hljs-keyword\">default<\/span> now()\n\n);\n\ncreate unique index unique_follow on user_followers(user_id, following_id);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><\/p>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li>Click on \u201cRun\u201d, It should look like the image below.<br><br><noscript><img decoding=\"async\" title=\"Creating Tables in Supabase Database\" class=\"wp-image-39238\" style=\"width: 100%;\" src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/create-supabase-database-tables.png\" alt=\"Create database tables in Supabase project setup\"><\/noscript><img decoding=\"async\" title=\"Creating Tables in Supabase Database\" class=\"wp-image-39238 lazyload\" style=\"width: 100%;\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" alt=\"Create database tables in Supabase project setup\" data-src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/create-supabase-database-tables.png\"><br><\/li>\n<\/ol>\n\n\n\n<p>3. Now, create a <code>profiles<\/code> table. Whenever any user signs up, we will save user_id and email in this profile table. Later, you can add other fields like full name, profile_pic, bio, etc.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Go to SQL Editor<\/li>\n\n\n\n<li>Paste the following code for creating a profiles table, and automatically insert a new profile when a user signs up<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">create table public.profiles (\n id uuid primary key references auth.users(id) on <span class=\"hljs-keyword\">delete<\/span> cascade,\n email text, \n created_at timestamp <span class=\"hljs-keyword\">default<\/span> now()\n);\n\ncreate <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">public<\/span>.<span class=\"hljs-title\">handle_new_user<\/span>(<span class=\"hljs-params\"><\/span>)\n<span class=\"hljs-title\">returns<\/span> <span class=\"hljs-title\">trigger<\/span> <span class=\"hljs-title\">as<\/span> <span class=\"hljs-title\">$$<\/span>\n<span class=\"hljs-title\">begin<\/span>\n  <span class=\"hljs-title\">insert<\/span> <span class=\"hljs-title\">into<\/span> <span class=\"hljs-title\">public<\/span>.<span class=\"hljs-title\">profiles<\/span> (<span class=\"hljs-params\">id, email<\/span>)\n  <span class=\"hljs-title\">values<\/span> (<span class=\"hljs-params\">new.id, new.email<\/span>);\n  <span class=\"hljs-title\">return<\/span> <span class=\"hljs-title\">new<\/span>;\n<span class=\"hljs-title\">end<\/span>;\n<span class=\"hljs-title\">$$<\/span> <span class=\"hljs-title\">language<\/span> <span class=\"hljs-title\">plpgsql<\/span> <span class=\"hljs-title\">security<\/span> <span class=\"hljs-title\">definer<\/span>;\n<span class=\"hljs-title\">create<\/span> <span class=\"hljs-title\">trigger<\/span> <span class=\"hljs-title\">on_auth_user_created<\/span>\n<span class=\"hljs-title\">after<\/span> <span class=\"hljs-title\">insert<\/span> <span class=\"hljs-title\">on<\/span> <span class=\"hljs-title\">auth<\/span>.<span class=\"hljs-title\">users<\/span>\n<span class=\"hljs-title\">for<\/span> <span class=\"hljs-title\">each<\/span> <span class=\"hljs-title\">row<\/span> <span class=\"hljs-title\">execute<\/span> <span class=\"hljs-title\">procedure<\/span> <span class=\"hljs-title\">public<\/span>.<span class=\"hljs-title\">handle_new_user<\/span>(<span class=\"hljs-params\"><\/span>);<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now, whenever a new user signs up, a matching row is inserted into profiles.<\/p>\n\n\n\n<p>Supabase automatically creates APIs and permissions for these tables. Let\u2019s use that next.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 3: Set Up Your Frontend with Vite<\/strong><\/h3>\n\n\n\n<p>We\u2019ll create our frontend using Vite + React + TypeScript:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">create<\/span> <span class=\"hljs-selector-tag\">vite<\/span><span class=\"hljs-keyword\">@latest<\/span> supabase-vite-demo -- --template react-ts\ncd supabase-vite-demo\nnpm install<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Install Supabase and react router:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">install<\/span> <span class=\"hljs-keyword\">@supabase<\/span>\/supabase-js\nnpm install react-router<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Then, initialize the client in src\/supabaseClient.ts:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> { createClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@supabase\/supabase-js'<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> supabaseUrl = <span class=\"hljs-string\">'https:\/\/your-project.supabase.co'<\/span>\n<span class=\"hljs-keyword\">const<\/span> supabaseAnonKey = <span class=\"hljs-string\">'your-anon-key'<\/span>\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> supabase = createClient(supabaseUrl, supabaseAnonKey)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Grab the key and URL from your Supabase dashboard under Settings &gt; Data API.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 4: Add User Authentication<\/strong><\/h3>\n\n\n\n<p>Let\u2019s build a simple login\/signup form.<\/p>\n\n\n\n<p>Create <code>src\/Auth.tsx<\/code>, The Auth page handles user authentication using Supabase. It provides:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Email &amp; Password Login<\/strong>: Users can securely sign in.<\/li>\n\n\n\n<li><strong>User Registration<\/strong>: New users can sign up with an email and password.<\/li>\n\n\n\n<li><strong>Error Feedback<\/strong>: Displays clear messages when authentication fails.<\/li>\n\n\n\n<li><strong>Loading States:<\/strong> Disables inputs and buttons during processing for better UX.<\/li>\n<\/ul>\n\n\n\n<p>This page is the entry point for accessing authenticated features in the app.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { supabase } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/supabaseClient'<\/span>\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Auth<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#091;email, setEmail] = useState(<span class=\"hljs-string\">''<\/span>)\n  <span class=\"hljs-keyword\">const<\/span> &#091;password, setPassword] = useState(<span class=\"hljs-string\">''<\/span>)\n  <span class=\"hljs-keyword\">const<\/span> &#091;error, setError] = useState&lt;string | <span class=\"hljs-literal\">null<\/span>&gt;(<span class=\"hljs-literal\">null<\/span>)\n  <span class=\"hljs-keyword\">const<\/span> &#091;signInLoading, setSignInLoading] = useState(<span class=\"hljs-literal\">false<\/span>)\n  <span class=\"hljs-keyword\">const<\/span> &#091;signUpLoading, setSignUpLoading] = useState(<span class=\"hljs-literal\">false<\/span>)\n\n  <span class=\"hljs-keyword\">const<\/span> handleSignUp = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n    <span class=\"hljs-keyword\">try<\/span> {\n      setError(<span class=\"hljs-literal\">null<\/span>)\n      setSignUpLoading(<span class=\"hljs-literal\">true<\/span>)\n      <span class=\"hljs-keyword\">const<\/span> { error } = <span class=\"hljs-keyword\">await<\/span> supabase.auth.signUp({ email, password })\n      <span class=\"hljs-keyword\">if<\/span> (error) <span class=\"hljs-keyword\">throw<\/span> error\n    } <span class=\"hljs-keyword\">catch<\/span> (err) {\n      setError(err <span class=\"hljs-keyword\">instanceof<\/span> <span class=\"hljs-built_in\">Error<\/span> ? err.message : <span class=\"hljs-string\">'An error occurred during sign up'<\/span>)\n    } <span class=\"hljs-keyword\">finally<\/span> {\n      setSignUpLoading(<span class=\"hljs-literal\">false<\/span>)\n    }\n  }\n\n  <span class=\"hljs-keyword\">const<\/span> handleSignIn = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n    <span class=\"hljs-keyword\">try<\/span> {\n      setError(<span class=\"hljs-literal\">null<\/span>)\n      setSignInLoading(<span class=\"hljs-literal\">true<\/span>)\n      <span class=\"hljs-keyword\">const<\/span> { error } = <span class=\"hljs-keyword\">await<\/span> supabase.auth.signInWithPassword({ email, password })\n      <span class=\"hljs-keyword\">if<\/span> (error) <span class=\"hljs-keyword\">throw<\/span> error\n    } <span class=\"hljs-keyword\">catch<\/span> (err) {\n      setError(err <span class=\"hljs-keyword\">instanceof<\/span> <span class=\"hljs-built_in\">Error<\/span> ? err.message : <span class=\"hljs-string\">'An error occurred during sign in'<\/span>)\n    } <span class=\"hljs-keyword\">finally<\/span> {\n      setSignInLoading(<span class=\"hljs-literal\">false<\/span>)\n    }\n  }\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"auth-container\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span>&gt;<\/span>Sign In \/ Sign Up<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n      {error &amp;&amp; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"error-message\"<\/span>&gt;<\/span>{error}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>}\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n        <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{email}<\/span>\n        <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{e<\/span> =&gt;<\/span> setEmail(e.target.value)}\n        placeholder=\"Email\"\n        disabled={signInLoading || signUpLoading}\n      \/&gt;\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n        <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{password}<\/span>\n        <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{e<\/span> =&gt;<\/span> setPassword(e.target.value)}\n        placeholder=\"Password\"\n        type=\"password\"\n        disabled={signInLoading || signUpLoading}\n      \/&gt;\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{handleSignIn}<\/span> <span class=\"hljs-attr\">disabled<\/span>=<span class=\"hljs-string\">{signInLoading<\/span> || <span class=\"hljs-attr\">signUpLoading<\/span>}&gt;<\/span>\n        {signInLoading ? 'Loading...' : 'Sign In'}\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{handleSignUp}<\/span> <span class=\"hljs-attr\">disabled<\/span>=<span class=\"hljs-string\">{signInLoading<\/span> || <span class=\"hljs-attr\">signUpLoading<\/span>}&gt;<\/span>\n        {signUpLoading ? 'Loading...' : 'Sign Up'}\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  )\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Update <code>App.tsx<\/code> with the below code. The App component manages routing and authentication state:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Session Handling<\/strong>: Listens for Supabase auth state changes to manage user sessions.<\/li>\n\n\n\n<li><strong>Conditional Rendering<\/strong>:\n<ul class=\"wp-block-list\">\n<li>If not authenticated, \u2192 shows the Auth page.<\/li>\n\n\n\n<li>If authenticated, \u2192 routes to Posts and Followers.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Routing<\/strong>: Uses React Router to navigate between pages, with \/posts as the default landing route after login.<\/li>\n<\/ul>\n\n\n\n<p>This is the central logic hub that controls what the user sees based on their login status.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> { useEffect, useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { supabase } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/supabaseClient'<\/span>\n<span class=\"hljs-keyword\">import<\/span> Auth <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/Auth'<\/span>\n<span class=\"hljs-keyword\">import<\/span> Posts <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/Posts'<\/span>\n<span class=\"hljs-keyword\">import<\/span> Followers <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/Followers'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { BrowserRouter <span class=\"hljs-keyword\">as<\/span> Router, Routes, Route, Navigate } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react-router'<\/span>\n<span class=\"hljs-keyword\">import<\/span> type { Session } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@supabase\/supabase-js'<\/span>\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'.\/App.css'<\/span>\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">App<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#091;session, setSession] = useState&lt;Session | <span class=\"hljs-literal\">null<\/span>&gt;(<span class=\"hljs-literal\">null<\/span>)\n\n  useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    supabase.auth.onAuthStateChange(<span class=\"hljs-function\">(<span class=\"hljs-params\">_event, session: Session | <span class=\"hljs-literal\">null<\/span><\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">if<\/span> (session) {\n        setSession(session)\n      } <span class=\"hljs-keyword\">else<\/span> {\n        setSession(<span class=\"hljs-literal\">null<\/span>)\n      }\n    })\n  }, &#091;])\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Router<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        {!session ? (\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Auth<\/span> \/&gt;<\/span>\n        ) : (\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Routes<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/posts\"<\/span> <span class=\"hljs-attr\">element<\/span>=<span class=\"hljs-string\">{<\/span>&lt;<span class=\"hljs-attr\">Posts<\/span> \/&gt;<\/span>} \/&gt;\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/followers\"<\/span> <span class=\"hljs-attr\">element<\/span>=<span class=\"hljs-string\">{<\/span>&lt;<span class=\"hljs-attr\">Followers<\/span> \/&gt;<\/span>} \/&gt;\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Route<\/span> <span class=\"hljs-attr\">path<\/span>=<span class=\"hljs-string\">\"\/\"<\/span> <span class=\"hljs-attr\">element<\/span>=<span class=\"hljs-string\">{<\/span>&lt;<span class=\"hljs-attr\">Navigate<\/span> <span class=\"hljs-attr\">to<\/span>=<span class=\"hljs-string\">\"\/posts\"<\/span> <span class=\"hljs-attr\">replace<\/span> \/&gt;<\/span>} \/&gt;\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Routes<\/span>&gt;<\/span>\n        )}\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Router<\/span>&gt;<\/span><\/span>\n  )\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> App<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 5: Create and Fetch Posts<\/strong><\/h3>\n\n\n\n<p>Create <code>src\/Posts.tsx<\/code>, The Posts page allows authenticated users to create and view posts in real time. Key features include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Post Creation<\/strong>: Users can add new posts with a title, content, and image URL.<\/li>\n\n\n\n<li><strong>Post Listing<\/strong>: Displays all posts from logged in user in reverse chronological order.<\/li>\n\n\n\n<li><strong>Authentication Integration<\/strong>: Users must be logged in to post; includes sign out functionality.<\/li>\n\n\n\n<li><strong>Error Handling &amp; Validation<\/strong>: Ensures all fields are filled before submission and displays helpful error messages.<\/li>\n\n\n\n<li><strong>Navigation<\/strong>: Links to the Followers page and handles user sign out.<\/li>\n<\/ul>\n\n\n\n<p>This page demonstrates basic CRUD and authentication features using the Supabase SDK with React. If you&#8217;re planning to scale or build a more sophisticated app, investing in<a href=\"https:\/\/mobisoftinfotech.com\/services\/web-application-development-company?utm_source=blog&amp;utm_campaign=supabase-react-typescript-tutorial_blog\"> expert web application development services<\/a> might be the right next step.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> { useEffect, useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { supabase } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/supabaseClient'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { Link } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react-router'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { useNavigate } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react-router'<\/span>\n\ntype Post = {\n  <span class=\"hljs-attr\">id<\/span>: string\n  <span class=\"hljs-attr\">title<\/span>: string\n  <span class=\"hljs-attr\">content<\/span>: string\n  <span class=\"hljs-attr\">created_at<\/span>: string\n  <span class=\"hljs-attr\">image_url<\/span>: string\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Posts<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#091;posts, setPosts] = useState&lt;Post&#091;]&gt;(&#091;])\n  <span class=\"hljs-keyword\">const<\/span> &#091;title, setTitle] = useState(<span class=\"hljs-string\">''<\/span>)\n  <span class=\"hljs-keyword\">const<\/span> &#091;content, setContent] = useState(<span class=\"hljs-string\">''<\/span>)\n  <span class=\"hljs-keyword\">const<\/span> &#091;imageUrl, setImageUrl] = useState(<span class=\"hljs-string\">''<\/span>)\n  <span class=\"hljs-keyword\">const<\/span> &#091;error, setError] = useState&lt;string | <span class=\"hljs-literal\">null<\/span>&gt;(<span class=\"hljs-literal\">null<\/span>)\n  <span class=\"hljs-keyword\">const<\/span> &#091;loading, setLoading] = useState(<span class=\"hljs-literal\">false<\/span>)\n  <span class=\"hljs-keyword\">const<\/span> navigate = useNavigate()\n\n  <span class=\"hljs-keyword\">const<\/span> fetchPosts = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n    <span class=\"hljs-keyword\">try<\/span> {\n      setError(<span class=\"hljs-literal\">null<\/span>)\n      <span class=\"hljs-keyword\">const<\/span> { data, error } = <span class=\"hljs-keyword\">await<\/span> supabase\n        .from(<span class=\"hljs-string\">'posts'<\/span>)\n        .select(<span class=\"hljs-string\">'*'<\/span>)\n        .order(<span class=\"hljs-string\">'created_at'<\/span>, { <span class=\"hljs-attr\">ascending<\/span>: <span class=\"hljs-literal\">false<\/span> })\n      <span class=\"hljs-keyword\">if<\/span> (error) <span class=\"hljs-keyword\">throw<\/span> error\n      setPosts(data || &#091;])\n    } <span class=\"hljs-keyword\">catch<\/span> (err) {\n      setError(err <span class=\"hljs-keyword\">instanceof<\/span> <span class=\"hljs-built_in\">Error<\/span> ? err.message : <span class=\"hljs-string\">'Failed to fetch posts'<\/span>)\n    }\n  }\n\n  <span class=\"hljs-keyword\">const<\/span> createPost = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n    <span class=\"hljs-keyword\">try<\/span> {\n      setError(<span class=\"hljs-literal\">null<\/span>)\n      setLoading(<span class=\"hljs-literal\">true<\/span>)\n      <span class=\"hljs-keyword\">const<\/span> user = (<span class=\"hljs-keyword\">await<\/span> supabase.auth.getUser()).data.user\n      <span class=\"hljs-keyword\">if<\/span> (!user) <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">'You must be logged in to create a post'<\/span>)\n      <span class=\"hljs-keyword\">if<\/span> (!title || !content || !imageUrl) <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">'All fields are required'<\/span>)\n      <span class=\"hljs-keyword\">const<\/span> { error } = <span class=\"hljs-keyword\">await<\/span> supabase.from(<span class=\"hljs-string\">'posts'<\/span>).insert({\n        title,\n        content,\n        <span class=\"hljs-attr\">user_id<\/span>: user.id,\n        <span class=\"hljs-attr\">image_url<\/span>: imageUrl,\n      })\n      <span class=\"hljs-keyword\">if<\/span> (error) <span class=\"hljs-keyword\">throw<\/span> error\n\n      setTitle(<span class=\"hljs-string\">''<\/span>)\n      setContent(<span class=\"hljs-string\">''<\/span>)\n      fetchPosts()\n    } <span class=\"hljs-keyword\">catch<\/span> (err) {\n      setError(err <span class=\"hljs-keyword\">instanceof<\/span> <span class=\"hljs-built_in\">Error<\/span> ? err.message : <span class=\"hljs-string\">'Failed to create post'<\/span>)\n    } <span class=\"hljs-keyword\">finally<\/span> {\n      setLoading(<span class=\"hljs-literal\">false<\/span>)\n    }\n  }\n  <span class=\"hljs-keyword\">const<\/span> handleSignOut = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n    <span class=\"hljs-keyword\">try<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> { error } = <span class=\"hljs-keyword\">await<\/span> supabase.auth.signOut()\n      <span class=\"hljs-keyword\">if<\/span> (error) <span class=\"hljs-keyword\">throw<\/span> error\n      navigate(<span class=\"hljs-string\">'\/'<\/span>)\n    } <span class=\"hljs-keyword\">catch<\/span> (err) {\n      setError(err <span class=\"hljs-keyword\">instanceof<\/span> <span class=\"hljs-built_in\">Error<\/span> ? err.message : <span class=\"hljs-string\">'Failed to sign out'<\/span>)\n    }\n  }\n\n  useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    fetchPosts()\n  }, &#091;])\n  \n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"posts-container\"<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"nav-links\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Link<\/span> <span class=\"hljs-attr\">to<\/span>=<span class=\"hljs-string\">\"\/followers\"<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"followers-link\"<\/span>&gt;<\/span>View Followers<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Link<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{handleSignOut}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"sign-out-btn\"<\/span>&gt;<\/span>Sign Out<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"create-post\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span>&gt;<\/span>Create Post<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n        {error &amp;&amp; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"error-message\"<\/span>&gt;<\/span>{error}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>}\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n          <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{title}<\/span>\n          <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{e<\/span> =&gt;<\/span> setTitle(e.target.value)}\n          placeholder=\"Title\"\n          disabled={loading}\n        \/&gt;\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">textarea<\/span>\n          <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{content}<\/span>\n          <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{e<\/span> =&gt;<\/span> setContent(e.target.value)}\n          placeholder=\"Content\"\n          disabled={loading}\n        \/&gt;\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{createPost}<\/span> <span class=\"hljs-attr\">disabled<\/span>=<span class=\"hljs-string\">{loading}<\/span>&gt;<\/span>\n          {loading ? 'Creating...' : 'Submit'}\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h3<\/span>&gt;<\/span>Posts<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h3<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"post-list\"<\/span>&gt;<\/span>\n        {posts.map(post =&gt; (\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{post.id}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"post-item\"<\/span>&gt;<\/span>\n            {post.image_url ? (\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span>\n                <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{post.image_url}<\/span>\n                <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">{post.title}<\/span>\n                <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">height:<\/span> '<span class=\"hljs-attr\">60px<\/span>' }}\n                <span class=\"hljs-attr\">onError<\/span>=<span class=\"hljs-string\">{(e)<\/span> =&gt;<\/span> {\n                  console.error('Image failed to load:', post.image_url);\n                  e.currentTarget.style.display = 'none';\n                }}\n              \/&gt;\n            ) : (\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>No image available<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n            )}\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h4<\/span>&gt;<\/span>{post.title}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h4<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{post.content}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">small<\/span>&gt;<\/span>{new Date(post.created_at).toLocaleString()}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">small<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        ))}\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  )\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 6: Add Real-Time Updates and Upload Images with Supabase Storage<\/strong><\/h3>\n\n\n\n<p>Now we will add the below code for posts to update live without a refresh with the help of Supabase\u2019s real time features.&nbsp;<\/p>\n\n\n\n<p>Add this to the Posts.tsx file after the fetchPosts():&nbsp;&nbsp;<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> channel = supabase\n      .channel(<span class=\"hljs-string\">'public:posts'<\/span>)\n      .on(<span class=\"hljs-string\">'postgres_changes'<\/span>, { <span class=\"hljs-attr\">event<\/span>: <span class=\"hljs-string\">'*'<\/span>, <span class=\"hljs-attr\">schema<\/span>: <span class=\"hljs-string\">'public'<\/span>, <span class=\"hljs-attr\">table<\/span>: <span class=\"hljs-string\">'posts'<\/span> }, () =&gt; {\n        fetchPosts()\n      })\n      .subscribe()\n\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      supabase.removeChannel(channel)\n    }\n  }, &#091;])\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now, every insert\/update\/delete will trigger a refresh of your posts.<br><br>Let\u2019s allow users to upload a file.<\/p>\n\n\n\n<p>Add to <code>Posts.tsx<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> uploadFile = <span class=\"hljs-keyword\">async<\/span> (e: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {\n    <span class=\"hljs-keyword\">try<\/span> {\n      setError(<span class=\"hljs-literal\">null<\/span>)\n      <span class=\"hljs-keyword\">const<\/span> file = e.target.files?.&#091;<span class=\"hljs-number\">0<\/span>]\n      <span class=\"hljs-keyword\">if<\/span> (!file) <span class=\"hljs-keyword\">return<\/span>\n\n      <span class=\"hljs-keyword\">const<\/span> { error, data } = <span class=\"hljs-keyword\">await<\/span> supabase.storage\n        .from(<span class=\"hljs-string\">'uploads'<\/span>)\n        .upload(<span class=\"hljs-string\">`public\/<span class=\"hljs-subst\">${file.name}<\/span>`<\/span>, file, { <span class=\"hljs-attr\">upsert<\/span>: <span class=\"hljs-literal\">true<\/span> })\n\n      <span class=\"hljs-keyword\">if<\/span> (error) <span class=\"hljs-keyword\">throw<\/span> error\n       <span class=\"hljs-keyword\">const<\/span> { <span class=\"hljs-attr\">data<\/span>: signedUrlData } = <span class=\"hljs-keyword\">await<\/span> supabase.storage\n        .from(<span class=\"hljs-string\">'uploads'<\/span>)\n        .createSignedUrl(data.path, <span class=\"hljs-number\">60<\/span> * <span class=\"hljs-number\">60<\/span> * <span class=\"hljs-number\">24<\/span> * <span class=\"hljs-number\">30<\/span>)\n      <span class=\"hljs-keyword\">if<\/span> (!signedUrlData) <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">'Failed to get signed URL'<\/span>)\n      setImageUrl(signedUrlData.signedUrl)\n      alert(<span class=\"hljs-string\">'File uploaded successfully!'<\/span>)\n    } <span class=\"hljs-keyword\">catch<\/span> (err) {\n      setError(err <span class=\"hljs-keyword\">instanceof<\/span> <span class=\"hljs-built_in\">Error<\/span> ? err.message : <span class=\"hljs-string\">'Failed to upload file'<\/span>)\n    }\n  }<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>And in JSX, after the textarea tag and above the submit button:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"file-upload\"<\/span>&gt;<\/span>\n   <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>     \n    <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"file\"<\/span>\n    <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{uploadFile}<\/span>\n    <span class=\"hljs-attr\">disabled<\/span>=<span class=\"hljs-string\">{loading}<\/span>\n    <span class=\"hljs-attr\">accept<\/span>=<span class=\"hljs-string\">\"image\/jpeg,image\/png,image\/gif,image\/webp\"<\/span>\n    \/&gt;<\/span>\n    {imageUrl &amp;&amp; (\n       <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"image-preview\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{imageUrl}<\/span> <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">\"Preview\"<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">maxWidth:<\/span> '<span class=\"hljs-attr\">200px<\/span>', <span class=\"hljs-attr\">marginTop:<\/span> '<span class=\"hljs-attr\">10px<\/span>' }} \/&gt;<\/span>\n       <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n     )}\n <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Make sure you first create a Storage Bucket named uploads in your Supabase dashboard.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 7: Create Followers Page<\/strong><\/h3>\n\n\n\n<p>Create <code>src\/Followers.tsx<\/code>, The Followers page provides a seamless interface for users to engage with the social aspect of the app. It includes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Followers &amp; Following Counts:<\/strong> Display real time stats showing how many users are following you and how many you are following.<\/li>\n\n\n\n<li><strong>User Directory:<\/strong> Browse a list of all registered users (excluding yourself), pulled from the profiles table.<br><strong>Follow \/ Unfollow Actions:<\/strong> Instantly follow or unfollow users with one click backed by real time database operations using Supabase React hooks.<\/li>\n\n\n\n<li><strong>Real time Updates:<\/strong> Changes in the user_followers table (like new follows or unfollows) are reflected live without requiring a page refresh, thanks to Supabase\u2019s real time subscription feature.<\/li>\n\n\n\n<li><strong>Integrated Supabase SDK<\/strong>: This page integrates Supabase\u2019s auth, from(&#8230;).select, insert, delete, and realtime features to provide a complete user interaction system.<\/li>\n<\/ul>\n\n\n\n<p>This page not only enables rich social interaction but also demonstrates how to build reactive, data driven interfaces with minimal backend code using Supabase React TypeScript integration.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> { useEffect, useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { supabase } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/supabaseClient'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { Link } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react-router'<\/span>\n\ninterface User {\n  <span class=\"hljs-attr\">id<\/span>: string\n  <span class=\"hljs-attr\">email<\/span>: string\n  <span class=\"hljs-attr\">username<\/span>: string\n}\n\ninterface Follower {\n  <span class=\"hljs-attr\">follower_id<\/span>: string\n  <span class=\"hljs-attr\">following_id<\/span>: string\n}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Followers<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#091;users, setUsers] = useState&lt;User&#091;]&gt;(&#091;])\n  <span class=\"hljs-keyword\">const<\/span> &#091;followers, setFollowers] = useState&lt;Follower&#091;]&gt;(&#091;])\n  <span class=\"hljs-keyword\">const<\/span> &#091;following, setFollowing] = useState&lt;Follower&#091;]&gt;(&#091;])\n  <span class=\"hljs-keyword\">const<\/span> &#091;currentUser, setCurrentUser] = useState&lt;User | <span class=\"hljs-literal\">null<\/span>&gt;(<span class=\"hljs-literal\">null<\/span>)\n\n  useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    fetchUsers()\n    fetchCurrentUser()\n  }, &#091;])\n\n  <span class=\"hljs-keyword\">const<\/span> fetchCurrentUser = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n    <span class=\"hljs-keyword\">const<\/span> { <span class=\"hljs-attr\">data<\/span>: { user } } = <span class=\"hljs-keyword\">await<\/span> supabase.auth.getUser()\n    <span class=\"hljs-keyword\">if<\/span> (user) {\n      <span class=\"hljs-keyword\">const<\/span> { data } = <span class=\"hljs-keyword\">await<\/span> supabase\n        .from(<span class=\"hljs-string\">'profiles'<\/span>)\n        .select(<span class=\"hljs-string\">'*'<\/span>)\n        .eq(<span class=\"hljs-string\">'id'<\/span>, user.id)\n        .single()\n      setCurrentUser(data)\n    }\n  }\n\n  <span class=\"hljs-keyword\">const<\/span> fetchUsers = <span class=\"hljs-keyword\">async<\/span> () =&gt; \n    <span class=\"hljs-keyword\">const<\/span> { <span class=\"hljs-attr\">data<\/span>: { user } } = <span class=\"hljs-keyword\">await<\/span> supabase.auth.getUser()\n    <span class=\"hljs-keyword\">if<\/span> (user) {\n      <span class=\"hljs-keyword\">const<\/span> { <span class=\"hljs-attr\">data<\/span>: usersData } = <span class=\"hljs-keyword\">await<\/span> supabase\n        .from(<span class=\"hljs-string\">'profiles'<\/span>)\n        .select(<span class=\"hljs-string\">'*'<\/span>)\n      <span class=\"hljs-keyword\">const<\/span> { <span class=\"hljs-attr\">data<\/span>: followingData } = <span class=\"hljs-keyword\">await<\/span> supabase\n        .from(<span class=\"hljs-string\">'user_followers'<\/span>)\n        .select(<span class=\"hljs-string\">'*'<\/span>)\n        .eq(<span class=\"hljs-string\">'user_id'<\/span>, user.id)\n      <span class=\"hljs-keyword\">const<\/span> { <span class=\"hljs-attr\">data<\/span>: followersData } = <span class=\"hljs-keyword\">await<\/span> supabase\n        .from(<span class=\"hljs-string\">'user_followers'<\/span>)\n        .select(<span class=\"hljs-string\">'*'<\/span>)\n        .eq(<span class=\"hljs-string\">'following_id'<\/span>, user.id)\n\n      setUsers(usersData || &#091;])\n      setFollowers(followersData || &#091;])\n      setFollowing(followingData || &#091;])\n    }\n  }\n\n  <span class=\"hljs-keyword\">const<\/span> handleFollow = <span class=\"hljs-keyword\">async<\/span> (userId: string) =&gt; {\n    <span class=\"hljs-keyword\">const<\/span> { <span class=\"hljs-attr\">data<\/span>: { user } } = <span class=\"hljs-keyword\">await<\/span> supabase.auth.getUser()\n    <span class=\"hljs-keyword\">if<\/span> (user) {\n      <span class=\"hljs-keyword\">const<\/span> { error } = <span class=\"hljs-keyword\">await<\/span> supabase\n        .from(<span class=\"hljs-string\">'user_followers'<\/span>)\n        .insert(&#091;\n          { <span class=\"hljs-attr\">user_id<\/span>: user.id, <span class=\"hljs-attr\">following_id<\/span>: userId }\n        ])\n\n      <span class=\"hljs-keyword\">if<\/span> (!error) {\n        fetchUsers()\n      }\n    }\n  }\n\n  <span class=\"hljs-keyword\">const<\/span> handleUnfollow = <span class=\"hljs-keyword\">async<\/span> (userId: string) =&gt; {\n    <span class=\"hljs-keyword\">const<\/span> { <span class=\"hljs-attr\">data<\/span>: { user } } = <span class=\"hljs-keyword\">await<\/span> supabase.auth.getUser()\n    <span class=\"hljs-keyword\">if<\/span> (user) {\n      <span class=\"hljs-keyword\">const<\/span> { error } = <span class=\"hljs-keyword\">await<\/span> supabase\n        .from(<span class=\"hljs-string\">'user_followers'<\/span>)\n        .delete()\n        .eq(<span class=\"hljs-string\">'user_id'<\/span>, user.id)\n        .eq(<span class=\"hljs-string\">'following_id'<\/span>, userId)\n\n      <span class=\"hljs-keyword\">if<\/span> (!error) {\n        fetchUsers()\n      }\n    }\n  }\n\n  <span class=\"hljs-keyword\">const<\/span> isFollowing = <span class=\"hljs-function\">(<span class=\"hljs-params\">userId: string<\/span>) =&gt;<\/span> {\n    <span class=\"hljs-keyword\">return<\/span> following.some(<span class=\"hljs-function\"><span class=\"hljs-params\">f<\/span> =&gt;<\/span> f.following_id === userId)\n  }\n\n  useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> channel = supabase\n      .channel(<span class=\"hljs-string\">'public:user_followers'<\/span>)\n      .on(<span class=\"hljs-string\">'postgres_changes'<\/span>, { <span class=\"hljs-attr\">event<\/span>: <span class=\"hljs-string\">'*'<\/span>, <span class=\"hljs-attr\">schema<\/span>: <span class=\"hljs-string\">'public'<\/span>, <span class=\"hljs-attr\">table<\/span>: <span class=\"hljs-string\">'user_followers'<\/span> }, () =&gt; {\n        fetchUsers()\n      })\n      .subscribe()\n\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      supabase.removeChannel(channel)\n    }\n  }, &#091;])\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"followers-container\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"followers-header\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span>&gt;<\/span>Users<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Link<\/span> <span class=\"hljs-attr\">to<\/span>=<span class=\"hljs-string\">\"\/posts\"<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"back-link\"<\/span>&gt;<\/span>Back to Posts<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Link<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"followers-stats\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"stat-box\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h3<\/span>&gt;<\/span>Followers<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h3<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{followers.length}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"stat-box\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h3<\/span>&gt;<\/span>Following<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h3<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{following.length}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"users-list\"<\/span>&gt;<\/span>\n        {users.map((user) =&gt; (\n          user.id !== currentUser?.id &amp;&amp; (\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{user.id}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"user-card\"<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"user-info\"<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h3<\/span>&gt;<\/span>{user.username || user.email}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h3<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n              {isFollowing(user.id) ? (\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span>\n                  <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"unfollow-btn\"<\/span>\n                  <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> handleUnfollow(user.id)}\n                &gt;\n                  Unfollow\n                <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n              ) : (\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span>\n                  <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"follow-btn\"<\/span>\n                  <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> handleFollow(user.id)}\n                &gt;\n                  Follow\n                <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n              )}\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          )\n        ))}\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  )\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Followers<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 8: Add styling for all the pages<\/strong><\/h3>\n\n\n\n<p>Update <code>App.css<\/code> with the following code<strong>:<\/strong><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-id\">#root<\/span> {\n  <span class=\"hljs-attribute\">max-width<\/span>: <span class=\"hljs-number\">1280px<\/span>;\n  <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0<\/span> auto;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">2rem<\/span>;\n  <span class=\"hljs-attribute\">text-align<\/span>: center;\n}\n<span class=\"hljs-selector-class\">.logo<\/span> {\n  <span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-number\">6em<\/span>;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">1.5em<\/span>;\n  <span class=\"hljs-attribute\">will-change<\/span>: filter;\n  <span class=\"hljs-attribute\">transition<\/span>: filter <span class=\"hljs-number\">300ms<\/span>;\n}\n<span class=\"hljs-selector-class\">.logo<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> {\n  <span class=\"hljs-attribute\">filter<\/span>: <span class=\"hljs-built_in\">drop-shadow<\/span>(<span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">2em<\/span> #<span class=\"hljs-number\">646<\/span>cffaa);\n}\n<span class=\"hljs-selector-class\">.logo<\/span><span class=\"hljs-selector-class\">.react<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> {\n  <span class=\"hljs-attribute\">filter<\/span>: <span class=\"hljs-built_in\">drop-shadow<\/span>(<span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">2em<\/span> #<span class=\"hljs-number\">61<\/span>dafbaa);\n}\n<span class=\"hljs-keyword\">@keyframes<\/span> logo-spin {\n  <span class=\"hljs-selector-tag\">from<\/span> {\n    <span class=\"hljs-attribute\">transform<\/span>: <span class=\"hljs-built_in\">rotate<\/span>(<span class=\"hljs-number\">0deg<\/span>);\n  }\n  <span class=\"hljs-selector-tag\">to<\/span> {\n    <span class=\"hljs-attribute\">transform<\/span>: <span class=\"hljs-built_in\">rotate<\/span>(<span class=\"hljs-number\">360deg<\/span>);\n  }\n}\n<span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">prefers-reduced-motion:<\/span> no-preference) {\n  <span class=\"hljs-selector-tag\">a<\/span><span class=\"hljs-selector-pseudo\">:nth-of-type(2)<\/span> <span class=\"hljs-selector-class\">.logo<\/span> {\n    <span class=\"hljs-attribute\">animation<\/span>: logo-spin infinite <span class=\"hljs-number\">20s<\/span> linear;\n  }\n}\n<span class=\"hljs-selector-class\">.card<\/span> {\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">2em<\/span>;\n}\n<span class=\"hljs-selector-class\">.read-the-docs<\/span> {\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#888<\/span>;\n}\n<span class=\"hljs-selector-class\">.auth-container<\/span> {\n  <span class=\"hljs-attribute\">max-width<\/span>: <span class=\"hljs-number\">400px<\/span>;\n  <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0<\/span> auto;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">2rem<\/span>;\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#f8f9fa<\/span>;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">8px<\/span>;\n  <span class=\"hljs-attribute\">box-shadow<\/span>: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">2px<\/span> <span class=\"hljs-number\">4px<\/span> <span class=\"hljs-built_in\">rgba<\/span>(<span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0.1<\/span>);\n}\n<span class=\"hljs-selector-class\">.auth-container<\/span> <span class=\"hljs-selector-tag\">h2<\/span> {\n  <span class=\"hljs-attribute\">margin-bottom<\/span>: <span class=\"hljs-number\">1.5rem<\/span>;\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#333<\/span>;\n}\n<span class=\"hljs-selector-class\">.auth-container<\/span> <span class=\"hljs-selector-tag\">input<\/span> {\n  <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">0.8rem<\/span>;\n  <span class=\"hljs-attribute\">margin-bottom<\/span>: <span class=\"hljs-number\">1rem<\/span>;\n  <span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">1px<\/span> solid <span class=\"hljs-number\">#ddd<\/span>;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">4px<\/span>;\n  <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">1rem<\/span>;\n}\n<span class=\"hljs-selector-class\">.auth-container<\/span> <span class=\"hljs-selector-tag\">button<\/span> {\n  <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">0.8rem<\/span>;\n  <span class=\"hljs-attribute\">margin-bottom<\/span>: <span class=\"hljs-number\">0.5rem<\/span>;\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#646cff<\/span>;\n  <span class=\"hljs-attribute\">color<\/span>: white;\n  <span class=\"hljs-attribute\">border<\/span>: none;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">4px<\/span>;\n  <span class=\"hljs-attribute\">cursor<\/span>: pointer;\n  <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">1rem<\/span>;\n  <span class=\"hljs-attribute\">transition<\/span>: background <span class=\"hljs-number\">0.3s<\/span>;\n}\n<span class=\"hljs-selector-class\">.auth-container<\/span> <span class=\"hljs-selector-tag\">button<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#535bf2<\/span>;\n}\n<span class=\"hljs-selector-class\">.posts-container<\/span> {\n  <span class=\"hljs-attribute\">max-width<\/span>: <span class=\"hljs-number\">800px<\/span>;\n  <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0<\/span> auto;\n}\n<span class=\"hljs-selector-class\">.create-post<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#f8f9fa<\/span>;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">1.5rem<\/span>;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">8px<\/span>;\n  <span class=\"hljs-attribute\">margin-bottom<\/span>: <span class=\"hljs-number\">2rem<\/span>;\n  <span class=\"hljs-attribute\">box-shadow<\/span>: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">2px<\/span> <span class=\"hljs-number\">4px<\/span> <span class=\"hljs-built_in\">rgba<\/span>(<span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0.1<\/span>);\n}\n<span class=\"hljs-selector-class\">.create-post<\/span> <span class=\"hljs-selector-tag\">h2<\/span> {\n  <span class=\"hljs-attribute\">margin-bottom<\/span>: <span class=\"hljs-number\">1rem<\/span>;\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#333<\/span>;\n}\n<span class=\"hljs-selector-class\">.create-post<\/span> <span class=\"hljs-selector-tag\">input<\/span>,\n<span class=\"hljs-selector-class\">.create-post<\/span> <span class=\"hljs-selector-tag\">textarea<\/span> {\n  <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">0.8rem<\/span>;\n  <span class=\"hljs-attribute\">margin-bottom<\/span>: <span class=\"hljs-number\">1rem<\/span>;\n  <span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">1px<\/span> solid <span class=\"hljs-number\">#ddd<\/span>;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">4px<\/span>;\n  <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">1rem<\/span>;\n}\n<span class=\"hljs-selector-class\">.create-post<\/span> <span class=\"hljs-selector-tag\">textarea<\/span> {\n  <span class=\"hljs-attribute\">min-height<\/span>: <span class=\"hljs-number\">100px<\/span>;\n  <span class=\"hljs-attribute\">resize<\/span>: vertical;\n}\n<span class=\"hljs-selector-class\">.create-post<\/span> <span class=\"hljs-selector-tag\">button<\/span> {\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">0.8rem<\/span> <span class=\"hljs-number\">1.5rem<\/span>;\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#646cff<\/span>;\n  <span class=\"hljs-attribute\">color<\/span>: white;\n  <span class=\"hljs-attribute\">border<\/span>: none;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">4px<\/span>;\n  <span class=\"hljs-attribute\">cursor<\/span>: pointer;\n  <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">1rem<\/span>;\n  <span class=\"hljs-attribute\">transition<\/span>: background <span class=\"hljs-number\">0.3s<\/span>;\n}\n<span class=\"hljs-selector-class\">.create-post<\/span> <span class=\"hljs-selector-tag\">button<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#535bf2<\/span>;\n}\n<span class=\"hljs-selector-class\">.post-list<\/span> {\n  <span class=\"hljs-attribute\">display<\/span>: flex;\n  <span class=\"hljs-attribute\">flex-direction<\/span>: row;\n  <span class=\"hljs-attribute\">gap<\/span>: <span class=\"hljs-number\">1.5rem<\/span>;\n  <span class=\"hljs-attribute\">flex-wrap<\/span>: wrap;\n}\n<span class=\"hljs-selector-class\">.post-item<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: white;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">1.5rem<\/span>;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">8px<\/span>;\n  <span class=\"hljs-attribute\">box-shadow<\/span>: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">2px<\/span> <span class=\"hljs-number\">4px<\/span> <span class=\"hljs-built_in\">rgba<\/span>(<span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0.1<\/span>);\n}\n<span class=\"hljs-selector-class\">.post-item<\/span> <span class=\"hljs-selector-tag\">h4<\/span> {\n  <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0.5rem<\/span> <span class=\"hljs-number\">0<\/span>;\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#333<\/span>;\n}\n<span class=\"hljs-selector-class\">.post-item<\/span> <span class=\"hljs-selector-tag\">p<\/span> {\n  <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">1rem<\/span> <span class=\"hljs-number\">0<\/span>;\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#666<\/span>;\n}\n<span class=\"hljs-selector-class\">.post-item<\/span> <span class=\"hljs-selector-tag\">small<\/span> {\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#888<\/span>;\n}\n<span class=\"hljs-selector-class\">.error-message<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#fee2e2<\/span>;\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#dc2626<\/span>;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">0.8rem<\/span>;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">4px<\/span>;\n  <span class=\"hljs-attribute\">margin-bottom<\/span>: <span class=\"hljs-number\">1rem<\/span>;\n  <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">0.9rem<\/span>;\n}\n<span class=\"hljs-selector-class\">.file-upload<\/span> {\n  <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">1rem<\/span> <span class=\"hljs-number\">0<\/span>;\n}\n<span class=\"hljs-selector-class\">.file-upload<\/span> <span class=\"hljs-selector-tag\">input<\/span><span class=\"hljs-selector-attr\">&#091;type=<span class=\"hljs-string\">\"file\"<\/span>]<\/span> {\n  <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">0.5rem<\/span>;\n  <span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">1px<\/span> dashed <span class=\"hljs-number\">#ddd<\/span>;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">4px<\/span>;\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#f8f9fa<\/span>;\n}\n<span class=\"hljs-selector-tag\">input<\/span>,\n<span class=\"hljs-selector-tag\">textarea<\/span> {\n  <span class=\"hljs-attribute\">box-sizing<\/span>: border-box;\n}\n<span class=\"hljs-selector-class\">.followers-container<\/span> {\n  <span class=\"hljs-attribute\">max-width<\/span>: <span class=\"hljs-number\">800px<\/span>;\n  <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0<\/span> auto;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">20px<\/span>;\n}\n<span class=\"hljs-selector-class\">.followers-header<\/span> {\n  <span class=\"hljs-attribute\">display<\/span>: flex;\n  <span class=\"hljs-attribute\">justify-content<\/span>: space-between;\n  <span class=\"hljs-attribute\">align-items<\/span>: center;\n  <span class=\"hljs-attribute\">margin-bottom<\/span>: <span class=\"hljs-number\">20px<\/span>;\n}\n<span class=\"hljs-selector-class\">.back-link<\/span> {\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#646cff<\/span>;\n  <span class=\"hljs-attribute\">text-decoration<\/span>: none;\n  <span class=\"hljs-attribute\">font-weight<\/span>: <span class=\"hljs-number\">500<\/span>;\n}\n<span class=\"hljs-selector-class\">.back-link<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> {\n  <span class=\"hljs-attribute\">text-decoration<\/span>: underline;\n}\n<span class=\"hljs-selector-class\">.followers-stats<\/span> {\n  <span class=\"hljs-attribute\">display<\/span>: flex;\n  <span class=\"hljs-attribute\">gap<\/span>: <span class=\"hljs-number\">20px<\/span>;\n  <span class=\"hljs-attribute\">margin-bottom<\/span>: <span class=\"hljs-number\">30px<\/span>;\n}\n<span class=\"hljs-selector-class\">.stat-box<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#1a1a1a<\/span>;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">15px<\/span> <span class=\"hljs-number\">25px<\/span>;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">8px<\/span>;\n  <span class=\"hljs-attribute\">text-align<\/span>: center;\n  <span class=\"hljs-attribute\">min-width<\/span>: <span class=\"hljs-number\">120px<\/span>;\n}\n<span class=\"hljs-selector-class\">.stat-box<\/span> <span class=\"hljs-selector-tag\">h3<\/span> {\n  <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0<\/span>;\n  <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">0.9em<\/span>;\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#888<\/span>;\n}\n<span class=\"hljs-selector-class\">.stat-box<\/span> <span class=\"hljs-selector-tag\">p<\/span> {\n  <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">5px<\/span> <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span>;\n  <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">1.5em<\/span>;\n  <span class=\"hljs-attribute\">font-weight<\/span>: bold;\n}\n<span class=\"hljs-selector-class\">.users-list<\/span> {\n  <span class=\"hljs-attribute\">display<\/span>: grid;\n  <span class=\"hljs-attribute\">gap<\/span>: <span class=\"hljs-number\">15px<\/span>;\n}\n<span class=\"hljs-selector-class\">.user-card<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#a4a0a0<\/span>;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">15px<\/span>;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">8px<\/span>;\n  <span class=\"hljs-attribute\">display<\/span>: flex;\n  <span class=\"hljs-attribute\">justify-content<\/span>: space-between;\n  <span class=\"hljs-attribute\">align-items<\/span>: center;\n}\n<span class=\"hljs-selector-class\">.user-info<\/span> <span class=\"hljs-selector-tag\">h3<\/span> {\n  <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">10px<\/span>;\n  <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">1.1em<\/span>;\n}\n<span class=\"hljs-selector-class\">.follow-btn<\/span>, <span class=\"hljs-selector-class\">.unfollow-btn<\/span> {\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">8px<\/span> <span class=\"hljs-number\">16px<\/span>;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">4px<\/span>;\n  <span class=\"hljs-attribute\">border<\/span>: none;\n  <span class=\"hljs-attribute\">cursor<\/span>: pointer;\n  <span class=\"hljs-attribute\">font-weight<\/span>: <span class=\"hljs-number\">500<\/span>;\n  <span class=\"hljs-attribute\">transition<\/span>: background-color <span class=\"hljs-number\">0.2s<\/span>;\n}\n<span class=\"hljs-selector-class\">.follow-btn<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#646cff<\/span>;\n  <span class=\"hljs-attribute\">color<\/span>: white;\n}\n<span class=\"hljs-selector-class\">.follow-btn<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#535bf2<\/span>;\n}\n<span class=\"hljs-selector-class\">.unfollow-btn<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#333<\/span>;\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#888<\/span>;\n}\n<span class=\"hljs-selector-class\">.unfollow-btn<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#444<\/span>;\n}\n<span class=\"hljs-selector-class\">.nav-links<\/span> {\n  <span class=\"hljs-attribute\">margin-bottom<\/span>: <span class=\"hljs-number\">20px<\/span>;\n  <span class=\"hljs-attribute\">display<\/span>: flex;\n  <span class=\"hljs-attribute\">gap<\/span>: <span class=\"hljs-number\">15px<\/span>;\n  <span class=\"hljs-attribute\">align-items<\/span>: center;\n}\n<span class=\"hljs-selector-class\">.followers-link<\/span> {\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#646cff<\/span>;\n  <span class=\"hljs-attribute\">text-decoration<\/span>: none;\n  <span class=\"hljs-attribute\">font-weight<\/span>: <span class=\"hljs-number\">500<\/span>;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">8px<\/span> <span class=\"hljs-number\">16px<\/span>;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">4px<\/span>;\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#1a1a1a<\/span>;\n  <span class=\"hljs-attribute\">display<\/span>: inline-block;\n}\n<span class=\"hljs-selector-class\">.followers-link<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#242424<\/span>;\n}\n<span class=\"hljs-selector-class\">.sign-out-btn<\/span> {\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">8px<\/span> <span class=\"hljs-number\">16px<\/span>;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">4px<\/span>;\n  <span class=\"hljs-attribute\">border<\/span>: none;\n  <span class=\"hljs-attribute\">cursor<\/span>: pointer;\n  <span class=\"hljs-attribute\">font-weight<\/span>: <span class=\"hljs-number\">500<\/span>;\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#dc2626<\/span>;\n  <span class=\"hljs-attribute\">color<\/span>: white;\n  <span class=\"hljs-attribute\">transition<\/span>: background-color <span class=\"hljs-number\">0.2s<\/span>;\n}\n<span class=\"hljs-selector-class\">.sign-out-btn<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#b91c1c<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 9: Secure the Table by RLS<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Set Row Level Security (RLS) rules in Supabase to protect data by enabling RLS for posts and user_followers tables and setting policies.<\/li>\n\n\n\n<li>To protect user data in Supabase, you need to enable Row Level Security and define specific policies. For example, in the user_followers table, we\u2019ll allow each user to read and write only their data, and in the posts table, allow users to read posts created by themselves or users they follow. Here\u2019s how to do it:<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading step-9-h4\"><strong>Step 1: Enable RLS for the posts Table<\/strong><\/h4>\n\n\n\n<ul class=\"wp-block-list step-9-ul\">\n<li>Go to the Table Editor in your Supabase project.<\/li>\n\n\n\n<li>Select the posts table<\/li>\n\n\n\n<li>Click the \u201cRLS Disabled\u201d button to enable Row-Level Security. This will activate RLS on the table.<br><br><noscript><img decoding=\"async\" class=\"wp-image-39206\" style=\"width: 100%;\" src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-rls-secure-table.png\" alt=\"Apply Supabase RLS to secure database tables in React\" title=\"Implementing RLS Security in Supabase with React\"><\/noscript><img decoding=\"async\" class=\"wp-image-39206 lazyload\" style=\"width: 100%;\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" alt=\"Apply Supabase RLS to secure database tables in React\" title=\"Implementing RLS Security in Supabase with React\" data-src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-rls-secure-table.png\"><\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading step-9-h4\"><strong>Step 2: Add Your First Policy \u2013 Allow Users to Insert Their Posts<\/strong><\/h4>\n\n\n\n<ul class=\"wp-block-list step-9-ul\">\n<li>Once RLS is enabled, click the \u201cAdd RLS Policy\u201d button.<\/li>\n\n\n\n<li>You\u2019ll be taken to a page that lists all RLS policies for the posts table. Since no policies exist yet, the list will be empty.<\/li>\n\n\n\n<li>Click Create Policy.<\/li>\n\n\n\n<li>A side panel will appear where you can define your policy.<\/li>\n\n\n\n<li>Select the INSERT operation and choose the \u201cEnable insert for users based on user_id\u201d template.<\/li>\n\n\n\n<li>You can customize the policy if needed, or stick with the default.<\/li>\n\n\n\n<li>Click \u201cSave Policy\u201d.<br><br><noscript><img decoding=\"async\" class=\"wp-image-39210\" style=\"width: 100%;\" src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-insert-user-posts.png\" alt=\"Supabase policy to allow users to insert their posts\" title=\"Insert Policy for User Posts in Supabase\"><\/noscript><img decoding=\"async\" class=\"wp-image-39210 lazyload\" style=\"width: 100%;\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" alt=\"Supabase policy to allow users to insert their posts\" title=\"Insert Policy for User Posts in Supabase\" data-src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-insert-user-posts.png\"><\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Follow the above Step 1 and Step 2 for enabling RLS and adding an Insert Policy for the user_followers table.<\/li>\n\n\n\n<li>Follow the above Step 1 for enabling RLS for the profiles table.<\/li>\n\n\n\n<li>Add a policy in the user_followers table &#8211; Enable delete for users based on user_id\n<ul class=\"wp-block-list\">\n<li>This policy will allow users to delete or unfollow users<\/li>\n\n\n\n<li>Follow the similar steps to add a policy and refer to the image below<br><br><noscript><img decoding=\"async\" class=\"wp-image-39214\" style=\"width: 100%;\" src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-delete-own-followers.png\" alt=\"Supabase policy to allow user-specific delete in the followers table\" title=\"Delete Own Followers Policy in Supabase\"><\/noscript><img decoding=\"async\" class=\"wp-image-39214 lazyload\" style=\"width: 100%;\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" alt=\"Supabase policy to allow user-specific delete in the followers table\" title=\"Delete Own Followers Policy in Supabase\" data-src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-delete-own-followers.png\"><br><br><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Add a policy in the profiles table &#8211; Enable read access for all users with the Authenticated role.\n<ul class=\"wp-block-list\">\n<li>Follow the similar steps, but here select template \u201cEnable read access for all users\u201d and set Target Roles as authenticated, and refer to the image below<br><br><noscript><img decoding=\"async\" class=\"wp-image-39217\" style=\"width: 100%;\" src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-read-profiles.png\" alt=\"Enable read access on profiles table for all users\" title=\"Public Read Access Policy for Supabase Profiles Table\"><\/noscript><img decoding=\"async\" class=\"wp-image-39217 lazyload\" style=\"width: 100%;\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" alt=\"Enable read access on profiles table for all users\" title=\"Public Read Access Policy for Supabase Profiles Table\" data-src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-read-profiles.png\"><br><br><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Add a second policy in the user_followers table &#8211; Enable users to view their data only\n<ul class=\"wp-block-list\">\n<li>Click \u201cAdd RLS Policy\u201d again.<\/li>\n\n\n\n<li>Choose the \u201cSELECT\u201d operation.<\/li>\n\n\n\n<li>Pick the \u201cEnable users to view their own data only\u201d template.<\/li>\n\n\n\n<li>Click \u201cSave Policy.\u201d<br><br><noscript><img decoding=\"async\" title=\"View Own Followers Policy in Supabas\" class=\"wp-image-39221\" style=\"width: 100%;\" src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-view-own-followers.png\" alt=\"Policy for users to view their followers in Supabase\"><\/noscript><img decoding=\"async\" title=\"View Own Followers Policy in Supabas\" class=\"wp-image-39221 lazyload\" style=\"width: 100%;\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" alt=\"Policy for users to view their followers in Supabase\" data-src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-view-own-followers.png\"><br><br><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Now, add a second policy in the posts table &#8211; Allow users to read posts created by themselves or users they follow\n<ul class=\"wp-block-list\">\n<li>Go to the SQL Editor<\/li>\n\n\n\n<li>Copy and paste the following code in the SQL editor for creating an RLS policy for the posts table.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">create policy <span class=\"hljs-string\">\"Allow reading own and followed users' posts\"<\/span>\non posts <span class=\"hljs-keyword\">for<\/span> select\nusing (\n  auth.uid() = user_id OR\n  exists (\n    select <span class=\"hljs-number\">1<\/span> <span class=\"hljs-keyword\">from<\/span> user_followers\n    where user_id = auth.uid()\n    and following_id = posts.user_id\n  )\n);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<ul class=\"wp-block-list step-9-h4\">\n<li>Click on the \u201cRun\u201d button<\/li>\n\n\n\n<li>Your new policy will be created for the posts table. Now go to the policies page to verify all the policies.<br><br><noscript><img decoding=\"async\" class=\"wp-image-39225\" style=\"width: 100%;\" src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-read-followed-posts.png\" alt=\"Supabase policy to read posts by self or followed users\" title=\"Read Access for Own and Followed Users\u2019 Posts\"><\/noscript><img decoding=\"async\" class=\"wp-image-39225 lazyload\" style=\"width: 100%;\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" alt=\"Supabase policy to read posts by self or followed users\" title=\"Read Access for Own and Followed Users\u2019 Posts\" data-src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-read-followed-posts.png\"><br><br><\/li>\n\n\n\n<li>Add last policy to the uploads storage bucket &#8211; Only authenticated user can fetch and upload into the storage bucket\n<ul class=\"wp-block-list\">\n<li>Go to Storage<\/li>\n\n\n\n<li>Click on \u201cPolicies\u201d under configuration<\/li>\n\n\n\n<li>Click on \u201cNew Policy\u201d for the uploads storage bucket<\/li>\n\n\n\n<li>Click&nbsp; on \u201cGet started quickly\u201d to create a policy from a template<\/li>\n\n\n\n<li>Now select \u201cGive users access to a folder only to authenticated users\u201d template<\/li>\n\n\n\n<li>Click on \u201cUse this template\u201d button<br><br><noscript><img decoding=\"async\" class=\"wp-image-39227\" style=\"width: 100%;\" src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-storage-upload.png\" alt=\"Apply Supabase storage bucket policy for file uploads\" title=\"Final Supabase Policy for Upload Storage\"><\/noscript><img decoding=\"async\" class=\"wp-image-39227 lazyload\" style=\"width: 100%;\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" alt=\"Apply Supabase storage bucket policy for file uploads\" title=\"Final Supabase Policy for Upload Storage\" data-src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-storage-upload.png\"><br><br><\/li>\n\n\n\n<li>Click on \u201cSelect\u201d and \u201cInsert\u201d check box in Allowed Operations<\/li>\n\n\n\n<li>Click on \u201cReview\u201d button<br><br><noscript><img decoding=\"async\" class=\"wp-image-39230\" style=\"width: 100%;\" src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-new-upload-policy.png\" alt=\"Add new Supabase policy for uploading files.\" title=\"Creating a New Upload Policy in Supabase\"><\/noscript><img decoding=\"async\" class=\"wp-image-39230 lazyload\" style=\"width: 100%;\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" alt=\"Add new Supabase policy for uploading files.\" title=\"Creating a New Upload Policy in Supabase\" data-src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-new-upload-policy.png\"><br><br><\/li>\n\n\n\n<li>Click on \u201cSave Policy\u201d Button<br><br><noscript><img decoding=\"async\" class=\"wp-image-39234\" style=\"width: 100%;\" src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/review-supabase-upload-policy.png\" alt=\"Review Supabase upload policy before applying\" title=\"Review Upload Policy Settings in Supabase\"><\/noscript><img decoding=\"async\" class=\"wp-image-39234 lazyload\" style=\"width: 100%;\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" alt=\"Review Supabase upload policy before applying\" title=\"Review Upload Policy Settings in Supabase\" data-src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/review-supabase-upload-policy.png\"><br><br><\/li>\n\n\n\n<li>Similarly, add Policies for \u201cOther policies under storage.objects\u201d and \u201cPolicies under storage.buckets\u201d options as per the below image.<br><br><noscript><img decoding=\"async\" class=\"wp-image-39236\" style=\"width: 100%;\" src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-storage-objects-policies.png\" alt=\"Additional Supabase storage policies for objects\" title=\"Manage Supabase Storage.Objects with Custom Policies\"><\/noscript><img decoding=\"async\" class=\"wp-image-39236 lazyload\" style=\"width: 100%;\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" alt=\"Additional Supabase storage policies for objects\" title=\"Manage Supabase Storage.Objects with Custom Policies\" data-src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-storage-objects-policies.png\"><br><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 10: Start the App<\/strong><\/h3>\n\n\n\n<p>Now that everything is set up, it&#8217;s time to run your app.<br>In your terminal, use the following command:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">npm run dev<\/code><\/span><\/pre>\n\n\n<p>This will start the development server. You can now open your browser and go to <code>http:\/\/localhost:5173<\/code> to see your Supabase-powered React app in action.<br>You should now see your Supabase-powered React app live and running.<\/p>\n\n\n\n<p>Try signing up using an email and password. Supabase will automatically send a confirmation email to verify your address. After confirming your email, you\u2019ll be able to log in using the same credentials.&nbsp;<\/p>\n\n\n\n<p>Now, after logging in, you can start creating posts by adding a title, content, and uploading an image. All your posts will be saved and automatically displayed on the same screen, giving you a real-time view of your content, a clear example of Supabase real-time React usage.<\/p>\n\n\n\n<p>If you\u2019d like to take this a step further and enhance your file upload UX with progress indicators, check out our<a href=\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/react-file-uploader-progress-bar-nodejs-typescript?utm_source=blog&amp;utm_campaign=supabase-react-typescript-tutorial_blog\"> React File Uploader with Progress Bar Tutorial<\/a> using Node.js and TypeScript.<\/p>\n\n\n\n<p>You can also navigate to the Followers page to view a list of users who follow you.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Recap: What You Learned About Supabase<\/strong><\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Set up a Postgres database with API access<\/li>\n\n\n\n<li>Used Supabase Auth to sign up\/in users<\/li>\n\n\n\n<li>Added file uploads with Supabase Storage<\/li>\n\n\n\n<li>Subscribed to real-time changes<\/li>\n\n\n\n<li>Used Row Level Security to protect data<\/li>\n\n\n\n<li>Built a full-stack app without writing a single backend route<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Final Thoughts<\/strong><\/h2>\n\n\n\n<p>Supabase gives you the power of a full backend, with the simplicity of modern tooling. Whether you&#8217;re a solo developer or part of a team, it scales with you and keeps things transparent and open source.<\/p>\n\n\n\n<p>You now have a solid foundation to build more powerful apps. Try adding user profiles, likes, comments, or even edge functions next.<\/p>\n\n\n\n<p>To explore the complete source code for this tutorial or contribute to improvements, feel free to check out the project on <a href=\"https:\/\/github.com\/mobisoftinfotech\/supabase-react-tutorial\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/mobisoftinfotech.com\/contact-us?utm_source=blog&amp;utm_medium=supabase-react-typescript-tutorial-cta2 \"><noscript><img decoding=\"async\" width=\"855\" height=\"363\" src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/build-with-right-tech-stack.png\" alt=\"Build your next big idea with the right tech stack.\" class=\"wp-image-39203\" title=\"Your Next Big Idea Deserves the Right Tech Stack\"><\/noscript><img decoding=\"async\" width=\"855\" height=\"363\" src=\"data:image\/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20855%20363%22%3E%3C%2Fsvg%3E\" alt=\"Build your next big idea with the right tech stack.\" class=\"wp-image-39203 lazyload\" title=\"Your Next Big Idea Deserves the Right Tech Stack\" data-src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/build-with-right-tech-stack.png\"><\/a><\/figure>\n\n\n<div class=\"related-posts-section\"><h2>Related Posts<\/h2><ul class=\"related-posts-list\"><li><a href=\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/apple-intelligence-story-cover-generator\">Apple Intelligence: Building a Story Cover Generator with Image Playground<\/a><\/li><li><a href=\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/apple-intelligence-apps-ios-26-on-device-ai-guide\">Building Apple Intelligence Apps on iOS 26: A Complete Guide to On-Device AI with Foundation Models<\/a><\/li><li><a href=\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/react-native-push-notifications-tutorial\">React Native Push Notifications Tutorial: How to Implement Push Notifications in React Native<\/a><\/li><li><a href=\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/mobile-app-development-partner-startups\">Mobile App Development: How to Choose the Right App Development Partner for Your Startup<\/a><\/li><li><a href=\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/flutter-charts-tutorial-6-types-with-code-samples\">Flutter Charts: Hands On Tutorial For 6 Different Types Of Charts With Code Samples<\/a><\/li><li><a href=\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/firebase-cloud-firestore-mobile-app-integration\">Step-by-Step Guide to Integrating Firebase Cloud Firestore into Your Mobile App<\/a><\/li><\/ul><\/div>\n\n\n<div class=\"modern-author-card\">\n    <div class=\"author-card-content\">\n        <div class=\"author-info-section\">\n            <div class=\"author-avatar\">\n                <noscript><img decoding=\"async\" src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/shubham-agarwal-profile.png\" alt=\"Shubham Agarwal\"><\/noscript><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" alt=\"Shubham Agarwal\" data-src=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/shubham-agarwal-profile.png\" class=\" lazyload\">\n            <\/div>\n            <div class=\"author-details\">\n                <h3 class=\"author-name\">Shubham Agarwal<\/h3>\n                <p class=\"author-title\">Principal Software Engineer<\/p>\n                <a href=\"javascript:void(0);\" class=\"read-more-link read-more-btn\" onclick=\"toggleAuthorBio(this); return false;\">Read more <noscript><img decoding=\"async\" src=\"\/assets\/images\/blog\/Vector.png\" alt=\"expand\" class=\"read-more-arrow down-arrow\"><\/noscript><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" alt=\"expand\" class=\"read-more-arrow down-arrow lazyload\" data-src=\"\/assets\/images\/blog\/Vector.png\"><\/a>\n                <div class=\"author-bio-expanded\">\n                    <p>Shubham Agarwal is a Principal Software Engineer at <a href=\"https:\/\/mobisoftinfotech.com\">Mobisoft Infotech<\/a> with nearly a decade of experience in building high-performance web applications and designing scalable software architectures. While he specializes in Python, Node.js, and React, his expertise spans a wide range of technologies across the full stack. Over the years, Shubham has led the end-to-end development of several successful products translating complex ideas into clean, maintainable, and future-ready solutions. He brings a strong product mindset, a deep understanding of systems design, and a passion for writing code that solves real-world problems.<\/p>\n                    <div class=\"author-social-links\"><div class=\"social-icon\"><a href=\"https:\/\/www.linkedin.com\/in\/ishubhagarwal\" target=\"_blank\" rel=\"nofollow noopener\"><i class=\"icon-sprite linkedin\"><\/i><\/a><\/div><\/div>\n                    <a href=\"javascript:void(0);\" class=\"read-more-link read-less-btn\" onclick=\"toggleAuthorBio(this); return false;\" style=\"display: none;\">Read less <noscript><img decoding=\"async\" src=\"\/assets\/images\/blog\/Vector.png\" alt=\"collapse\" class=\"read-more-arrow up-arrow\"><\/noscript><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" alt=\"collapse\" class=\"read-more-arrow up-arrow lazyload\" data-src=\"\/assets\/images\/blog\/Vector.png\"><\/a>\n                <\/div>\n            <\/div>\n        <\/div>\n        <div class=\"share-section\">\n            <span class=\"share-label\">Share Article<\/span>\n            <div class=\"social-share-buttons\">\n                <a href=\"https:\/\/www.facebook.com\/sharer\/sharer.php?u=https%3A%2F%2Fmobisoftinfotech.com%2Fresources%2Fblog%2Fapp-development%2Fsupabase-react-typescript-tutorial\" target=\"_blank\" class=\"share-btn facebook-share\"><i class=\"fa fa-facebook-f\"><\/i><\/a>\n                <a href=\"https:\/\/www.linkedin.com\/sharing\/share-offsite\/?url=https%3A%2F%2Fmobisoftinfotech.com%2Fresources%2Fblog%2Fapp-development%2Fsupabase-react-typescript-tutorial\" target=\"_blank\" class=\"share-btn linkedin-share\"><i class=\"fa fa-linkedin\"><\/i><\/a>\n            <\/div>\n        <\/div>\n    <\/div>\n<\/div>\n\n\n\n<style>\nul.wp-block-list.step-9-ul {\n    margin-left: 50px;\n}\n.step-9-h4{padding-left:15px;}\n.post-content p{\n    margin: 20px 0 20px;\n}\n.border-to-img img {\n    border-radius: 20px;\n}\n.border-to-img{\nborder: 1px solid #babab9;\n    border-radius: 15px;\n}\n.hljs-keyword, .hljs-title {\n    font-weight: normal !important;\n}\n\nspan.hljs-attribute, .hljs-selector-tag {\n    font-weight: normal;\n}\nh5.wp-block-heading{\nfont-size:20px;\n}\nh4.wp-block-heading{\nfont-size:20px;\n}\nh3.wp-block-heading{\nfont-size:22px;\n}\nh4.wp-block-heading.h4-list {\n    position: relative;\nfont-size:20px;\n    padding-left: 20px;\n}\n\nh4.wp-block-heading.h4-list:before {\n    position: absolute;\n    content: '';\n    background: #0d265c;\n    height: 9px;\n    width: 9px;\n    left: 0;\n    border-radius: 50px;\n    top: 8px;\n}\n@media only screen and (max-width: 991px) {\nul.wp-block-list.step-9-ul {\n    margin-left: 0px;\n}\n.step-9-h4{padding-left:0px;}\n    .post-content li {\n       padding-left: 25px;\n    }\n    .post-content li:before {\n        content: '';\n         width: 9px;\n        height: 9px;\n        background-color: #0d265c;\n        border-radius: 50%;\n        position: absolute;\n        left: 0px;\n        top: 12px;\n    }\n}\n<\/style>\n<script type=\"application\/ld+json\">\n{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"Article\",\n  \"mainEntityOfPage\": {\n    \"@type\": \"WebPage\",\n    \"@id\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\"\n  },\n  \"headline\": \"Supabase React Tutorial: Creating a Supabase Project with React and TypeScript\",\n  \"description\": \"Learn how to build a full-stack app using Supabase, React, and TypeScript with real time features, auth, storage, and more step-by-step guide.\",\n  \"image\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-react-typescript-tutorial\",\n  \"author\": {\n    \"@type\": \"Person\",\n    \"name\": \"Shubham Agarwal\",\n    \"description\": \"Shubham Agarwal is a Principal Software Engineer at Mobisoft Infotech with nearly a decade of experience in building high-performance web applications and designing scalable software architectures. While he specializes in Python, Node.js, and React, his expertise spans a wide range of technologies across the full stack. Over the years, Shubham has led the end-to-end development of several successful products translating complex ideas into clean, maintainable, and future-ready solutions. He brings a strong product mindset, a deep understanding of systems design, and a passion for writing code that solves real-world problems.\"\n  },\n  \"publisher\": {\n    \"@type\": \"Organization\",\n    \"name\": \"Mobisoft Infotech\",\n    \"logo\": {\n      \"@type\": \"ImageObject\",\n      \"url\": \"https:\/\/mobisoftinfotech.com\/assets\/images\/mshomepage\/MI_Logo-white.svg\",\n      \"width\": 600,\n      \"height\": 600\n    }\n  },\n  \"datePublished\": \"2025-06-06\",\n  \"dateModified\": \"2025-06-06\"\n}\n<\/script>\n<script type=\"application\/ld+json\">\n{\n    \"@context\": \"https:\/\/schema.org\",\n    \"@type\": \"LocalBusiness\",\n    \"name\": \"Mobisoft Infotech\",\n    \"url\": \"https:\/\/mobisoftinfotech.com\",\n    \"logo\": \"https:\/\/mobisoftinfotech.com\/assets\/images\/mshomepage\/MI_Logo-white.svg\",\n    \"description\": \"Mobisoft Infotech specializes in custom software development and digital solutions.\",\n    \"address\": {\n        \"@type\": \"PostalAddress\",\n        \"streetAddress\": \"5718 Westheimer Rd Suite 1000\",\n        \"addressLocality\": \"Houston\",\n        \"addressRegion\": \"TX\",\n        \"postalCode\": \"77057\",\n        \"addressCountry\": \"USA\"\n    },\n    \"contactPoint\": [{\n        \"@type\": \"ContactPoint\",\n        \"telephone\": \"+1-855-572-2777\",\n        \"contactType\": \"Customer Service\",\n        \"areaServed\": [\"USA\", \"Worldwide\"],\n        \"availableLanguage\": [\"English\"]\n    }],\n    \"sameAs\": [\n        \"https:\/\/www.facebook.com\/pages\/Mobisoft-Infotech\/131035500270720\",\n        \"https:\/\/x.com\/MobisoftInfo\",\n        \"https:\/\/www.linkedin.com\/company\/mobisoft-infotech\",\n        \"https:\/\/in.pinterest.com\/mobisoftinfotech\/\",\n        \"https:\/\/www.instagram.com\/mobisoftinfotech\/\",\n        \"https:\/\/github.com\/MobisoftInfotech\",\n        \"https:\/\/www.behance.net\/MobisoftInfotech\",\n        \"https:\/\/www.youtube.com\/@MobisoftinfotechHouston\"\n    ]\n}\n<\/script>\n<script type=\"application\/ld+json\">\n{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"Organization\",\n  \"name\": \"Mobisoft Infotech\",\n  \"url\": \"https:\/\/mobisoftinfotech.com\/\",\n  \"logo\": \"https:\/\/mobisoftinfotech.com\/assets\/images\/MI_Logo.svg\",\n  \"sameAs\": [\n    \"https:\/\/www.facebook.com\/pages\/Mobisoft-Infotech\/131035500270720\",\n    \"https:\/\/twitter.com\/MobisoftInfo\",\n    \"https:\/\/www.instagram.com\/mobisoftinfotech\/\",\n    \"https:\/\/www.youtube.com\/@MobisoftinfotechHouston\",\n    \"https:\/\/www.linkedin.com\/company\/mobisoft-infotech\",\n    \"https:\/\/in.pinterest.com\/mobisoftinfotech\/\",\n    \"https:\/\/github.com\/MobisoftInfotech\"\n  ],\n  \"contactPoint\": [\n    {\n      \"@type\": \"ContactPoint\",\n      \"telephone\": \"+1-855-572-2777\",\n      \"contactType\": \"Customer Service\",\n      \"areaServed\": \"US\",\n      \"availableLanguage\": [\"English\"]\n    },\n    {\n      \"@type\": \"ContactPoint\",\n      \"telephone\": \"+91-858-600-8627\",\n      \"contactType\": \"Customer Service\",\n      \"areaServed\": \"IN\",\n      \"availableLanguage\": [\"English\"]\n    }\n  ]\n}\n<\/script>\n<script type=\"application\/ld+json\">\n    [\n    {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/reactjs-frontend-expertise.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"ReactJS Expertise to Power Your Frontend\",\n            \"caption\": \"Unlock frontend performance and scalability with ReactJS experts.\",\n            \"description\": \"Boost your web app\u2019s user experience by leveraging professional ReactJS development aligned with Supabase projects.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/reactjs-frontend-expertise.png\"\n        },\n        {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/build-with-right-tech-stack.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"Your Next Big Idea Deserves the Right Tech Stack\",\n            \"caption\": \"React, Supabase, and TypeScript are a powerful combo for innovation.\",\n            \"description\": \"Accelerate innovation using a modern tech stack centered around React, Supabase, and TypeScript.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/build-with-right-tech-stack.png\"\n        },\n        {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-react-typescript-tutorial.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"Supabase React Tutorial: Creating a Supabase Project with React and TypeScrip\",\n            \"caption\": \"A hands on tutorial on setting up a Supabase project using React and TypeScript.\",\n            \"description\": \"Learn how to build a real-time, secure, scalable application using React, Supabase, and TypeScript.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-react-typescript-tutorial.png\"\n        },\n        {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-auth-react-native.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"Supabase Authentication for React Native Apps\",\n            \"caption\": \"Secure your mobile apps with Supabase Auth in React Native.\",\n            \"description\": \" Implement secure login, signup, and session handling using Supabase's authentication module in React Native.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-auth-react-native.png\"\n        },\n        {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-storage-react-native.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"Supabase Storage Integration in React Native\",\n            \"caption\": \"Add cloud file handling to your mobile app using Supabase Storage.\",\n            \"description\": \"Handle user uploads, media files, and document storage using Supabase's scalable file storage in React Native.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-storage-react-native.png\"\n        },\n        {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-rls-secure-table.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"Implementing RLS Security in Supabase with React\",\n            \"caption\": \"Use Row Level Security to manage access control within Supabase from a React app.\",\n            \"description\": \"Learn how to use Supabase's Row Level Security to secure sensitive data at a per user level in React apps.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-rls-secure-table.png\"\n        },\n        {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-insert-user-posts.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"Insert Policy for User Posts in Supabase\",\n            \"caption\": \"Enable users to add their content securely using Supabase policies.\",\n            \"description\": \"Set up a Supabase policy allowing authenticated users to insert their posts in a React app.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-insert-user-posts.png\"\n        },\n        {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-view-own-followers.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"View Own Followers Policy in Supabase\",\n            \"caption\": \"Control access so users can only view their followers.\",\n            \"description\": \"Set up RLS in Supabase to ensure users only access follower data relevant to them.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-view-own-followers.png\"\n        },\n        {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-delete-own-followers.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"Delete Own Followers Policy in Supabase\",\n            \"caption\": \"Let users manage their follower data via secure RLS policies.\",\n            \"description\": \"Learn to configure delete permissions on the user_followers table using RLS by user_id.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-delete-own-followers.png\"\n        },\n        {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-read-followed-posts.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"Read Access for Own and Followed Users\u2019 Posts\",\n            \"caption\": \"Customize post visibility using Supabase policy conditions.\",\n            \"description\": \"Define a Supabase policy that enables users to view posts by themselves or users they follow.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-read-followed-posts.png\"\n        },\n        {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-storage-upload.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"Final Supabase Policy for Upload Storage\",\n            \"caption\": \"Secure your file storage in Supabase with controlled access rules.\",\n            \"description\": \"Restrict and secure storage bucket access in Supabase with final row-level policies for uploads.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-policy-storage-upload.png\"\n        },\n        {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-new-upload-policy.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"Creating a New Upload Policy in Supabase\",\n            \"caption\": \"Define upload access control with Supabase\u2019s security layers.\",\n            \"description\": \"Learn how to create new policies for secure file uploads in Supabase from a React-based app.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-new-upload-policy.png\"\n        },\n        {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/review-supabase-upload-policy.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"Review Upload Policy Settings in Supabase\",\n            \"caption\": \"Validate and finalize policy rules before storage implementation.\",\n            \"description\": \"Ensure that upload-related policies are properly reviewed and structured for React + Supabase integration.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/review-supabase-upload-policy.png\"\n        },\n        {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-storage-objects-policies.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"Manage Supabase Storage.Objects with Custom Policies\",\n            \"caption\": \"Control file-level access using Supabase storage object policies.\",\n            \"description\": \"Explore advanced Supabase storage policies to manage file access at the object level in React apps.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-storage-objects-policies.png\"\n        },\n        {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/shubham-agarwal-profile.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"Shubham Agarwal, Author of Supabase React Tutorial\",\n            \"caption\": \"Written by Shubham Agarwal, React & Supabase developer and educator.\",\n            \"description\": \"Shubham Agarwal shares deep insights on building scalable, real-time apps using React, Supabase, and TypeScript.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/shubham-agarwal-profile.png\"\n        },\n        {\n            \"@context\": \"https:\/\/schema.org\",\n            \"@type\": \"ImageObject\",\n            \"contentUrl\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/create-supabase-database-tables.png\",\n            \"url\": \"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\n            \"name\": \"Creating Tables in Supabase Database\",\n            \"caption\": \"Define your application's data structure by creating tables in Supabase.\",\n            \"description\": \"Learn how to set up and structure your database by creating tables in Supabase for seamless integration with your React and TypeScript application.\",\n            \"license\": \"https:\/\/mobisoftinfotech.com\/terms\",\n            \"acquireLicensePage\": \"https:\/\/mobisoftinfotech.com\/acquire-license\",\n            \"creditText\": \"Mobisoft Infotech\",\n            \"copyrightNotice\": \"Mobisoft Infotech\",\n            \"creator\": {\n                \"@type\": \"Organization\",\n                \"name\": \"Mobisoft Infotech\"\n            },\n            \"thumbnail\": \"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/create-supabase-database-tables.png\"\n        }\n        ]\n    <\/script>\n","protected":false},"excerpt":{"rendered":"<p>If you&#8217;re exploring modern backend tools that feel like magic, Supabase should be on your radar. It\u2019s open source, fast to set up, and offers a full suite of features: a database, authentication, storage, and real-time subscriptions all powered by Postgres.&nbsp; In this tutorial, we\u2019ll walk through building a simple web app using Supabase, React, [&hellip;]<\/p>\n","protected":false},"author":115,"featured_media":39197,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_s2mail":"","footnotes":""},"categories":[5028],"tags":[5968,5964,5962,5967,5965,5966,5961,5969,5960,5971,5972,5974,5970,5973,5981,5977,5978,5979,5976,5975,5963,5980],"class_list":["post-39183","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-app-development","tag-postgresql-integration-in-react-apps","tag-react-native-supabase","tag-react-supabase","tag-react-typescript-crud-app","tag-serverless-database-with-supabase","tag-supabase-authentication-react","tag-supabase-react","tag-supabase-react-hooks","tag-supabase-react-native","tag-supabase-react-next-js","tag-supabase-react-project","tag-supabase-react-starter-template","tag-supabase-react-tutorial","tag-supabase-real-time-react","tag-supabase-realtime-subscriptions-in-react","tag-supabase-row-level-security-in-react","tag-supabase-storage-integration-with-react","tag-supabase-typescrip","tag-supabase-typescript-integration","tag-supabase-typescript-setup","tag-supabase-typescript-types-generation","tag-supabase-vs-firebase-for-react-developers"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.2 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Build a Supabase Project with React and TypeScript Tutorial<\/title>\n<meta name=\"description\" content=\"Learn how to build a full-stack app using Supabase, React, TypeScript with user authentication, database integration, file storage, real-time updates and more step-by-step guide.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Build a Supabase Project with React and TypeScript Tutorial\" \/>\n<meta property=\"og:description\" content=\"Learn how to build a full-stack app using Supabase, React, TypeScript with user authentication, database integration, file storage, real-time updates and more step-by-step guide.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\" \/>\n<meta property=\"og:site_name\" content=\"Mobisoft Infotech\" \/>\n<meta property=\"article:published_time\" content=\"2025-06-06T04:59:01+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-11-03T13:18:36+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/og-Supabase-React-Tutorial.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1000\" \/>\n\t<meta property=\"og:image:height\" content=\"525\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Shubham Agarwal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Shubham Agarwal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial#article\",\"isPartOf\":{\"@id\":\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\"},\"author\":{\"name\":\"Shubham Agarwal\",\"@id\":\"https:\/\/mobisoftinfotech.com\/resources\/#\/schema\/person\/bca2da51a24299ab60cb8b27cae32db7\"},\"headline\":\"Supabase React Tutorial: Creating a Supabase Project with React and TypeScript\",\"datePublished\":\"2025-06-06T04:59:01+00:00\",\"dateModified\":\"2025-11-03T13:18:36+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\"},\"wordCount\":1931,\"image\":{\"@id\":\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial#primaryimage\"},\"thumbnailUrl\":\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-react-typescript-tutorial.png\",\"keywords\":[\"postgresql integration in react apps\",\"react native supabase\",\"react supabase\",\"react typescript crud app\",\"serverless database with supabase\",\"supabase authentication react\",\"supabase react\",\"supabase react hooks\",\"supabase react native\",\"supabase react next.js\",\"supabase react project\",\"supabase react starter template\",\"supabase react tutorial\",\"supabase real-time react\",\"supabase realtime subscriptions in react\",\"supabase row level security in react\",\"supabase storage integration with react\",\"supabase typescrip\",\"supabase typescript integration\",\"supabase typescript setup\",\"supabase typescript types generation\",\"supabase vs firebase for react developers\"],\"articleSection\":[\"App Development\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\"url\":\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\",\"name\":\"Build a Supabase Project with React and TypeScript Tutorial\",\"isPartOf\":{\"@id\":\"https:\/\/mobisoftinfotech.com\/resources\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial#primaryimage\"},\"image\":{\"@id\":\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial#primaryimage\"},\"thumbnailUrl\":\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-react-typescript-tutorial.png\",\"datePublished\":\"2025-06-06T04:59:01+00:00\",\"dateModified\":\"2025-11-03T13:18:36+00:00\",\"author\":{\"@id\":\"https:\/\/mobisoftinfotech.com\/resources\/#\/schema\/person\/bca2da51a24299ab60cb8b27cae32db7\"},\"description\":\"Learn how to build a full-stack app using Supabase, React, TypeScript with user authentication, database integration, file storage, real-time updates and more step-by-step guide.\",\"breadcrumb\":{\"@id\":\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial#primaryimage\",\"url\":\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-react-typescript-tutorial.png\",\"contentUrl\":\"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-react-typescript-tutorial.png\",\"width\":855,\"height\":392,\"caption\":\"Supabase React tutorial using TypeScript integration\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/mobisoftinfotech.com\/resources\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Supabase React Tutorial: Creating a Supabase Project with React and TypeScript\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/mobisoftinfotech.com\/resources\/#website\",\"url\":\"https:\/\/mobisoftinfotech.com\/resources\/\",\"name\":\"Mobisoft Infotech\",\"description\":\"Discover Mobility\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/mobisoftinfotech.com\/resources\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/mobisoftinfotech.com\/resources\/#\/schema\/person\/bca2da51a24299ab60cb8b27cae32db7\",\"name\":\"Shubham Agarwal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/0f49f7e61c4dcd39d24de193c609fc9713af2c8638b8d56f2c3579fc975da802?s=96&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/0f49f7e61c4dcd39d24de193c609fc9713af2c8638b8d56f2c3579fc975da802?s=96&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/0f49f7e61c4dcd39d24de193c609fc9713af2c8638b8d56f2c3579fc975da802?s=96&r=g\",\"caption\":\"Shubham Agarwal\"},\"sameAs\":[\"https:\/\/mobisoftinfotech.com\/\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Build a Supabase Project with React and TypeScript Tutorial","description":"Learn how to build a full-stack app using Supabase, React, TypeScript with user authentication, database integration, file storage, real-time updates and more step-by-step guide.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial","og_locale":"en_US","og_type":"article","og_title":"Build a Supabase Project with React and TypeScript Tutorial","og_description":"Learn how to build a full-stack app using Supabase, React, TypeScript with user authentication, database integration, file storage, real-time updates and more step-by-step guide.","og_url":"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial","og_site_name":"Mobisoft Infotech","article_published_time":"2025-06-06T04:59:01+00:00","article_modified_time":"2025-11-03T13:18:36+00:00","og_image":[{"width":1000,"height":525,"url":"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/og-Supabase-React-Tutorial.png","type":"image\/png"}],"author":"Shubham Agarwal","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Shubham Agarwal","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial#article","isPartOf":{"@id":"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial"},"author":{"name":"Shubham Agarwal","@id":"https:\/\/mobisoftinfotech.com\/resources\/#\/schema\/person\/bca2da51a24299ab60cb8b27cae32db7"},"headline":"Supabase React Tutorial: Creating a Supabase Project with React and TypeScript","datePublished":"2025-06-06T04:59:01+00:00","dateModified":"2025-11-03T13:18:36+00:00","mainEntityOfPage":{"@id":"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial"},"wordCount":1931,"image":{"@id":"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial#primaryimage"},"thumbnailUrl":"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-react-typescript-tutorial.png","keywords":["postgresql integration in react apps","react native supabase","react supabase","react typescript crud app","serverless database with supabase","supabase authentication react","supabase react","supabase react hooks","supabase react native","supabase react next.js","supabase react project","supabase react starter template","supabase react tutorial","supabase real-time react","supabase realtime subscriptions in react","supabase row level security in react","supabase storage integration with react","supabase typescrip","supabase typescript integration","supabase typescript setup","supabase typescript types generation","supabase vs firebase for react developers"],"articleSection":["App Development"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial","url":"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial","name":"Build a Supabase Project with React and TypeScript Tutorial","isPartOf":{"@id":"https:\/\/mobisoftinfotech.com\/resources\/#website"},"primaryImageOfPage":{"@id":"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial#primaryimage"},"image":{"@id":"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial#primaryimage"},"thumbnailUrl":"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-react-typescript-tutorial.png","datePublished":"2025-06-06T04:59:01+00:00","dateModified":"2025-11-03T13:18:36+00:00","author":{"@id":"https:\/\/mobisoftinfotech.com\/resources\/#\/schema\/person\/bca2da51a24299ab60cb8b27cae32db7"},"description":"Learn how to build a full-stack app using Supabase, React, TypeScript with user authentication, database integration, file storage, real-time updates and more step-by-step guide.","breadcrumb":{"@id":"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial#primaryimage","url":"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-react-typescript-tutorial.png","contentUrl":"https:\/\/mobisoftinfotech.com\/resources\/wp-content\/uploads\/2025\/06\/supabase-react-typescript-tutorial.png","width":855,"height":392,"caption":"Supabase React tutorial using TypeScript integration"},{"@type":"BreadcrumbList","@id":"https:\/\/mobisoftinfotech.com\/resources\/blog\/app-development\/supabase-react-typescript-tutorial#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/mobisoftinfotech.com\/resources\/"},{"@type":"ListItem","position":2,"name":"Supabase React Tutorial: Creating a Supabase Project with React and TypeScript"}]},{"@type":"WebSite","@id":"https:\/\/mobisoftinfotech.com\/resources\/#website","url":"https:\/\/mobisoftinfotech.com\/resources\/","name":"Mobisoft Infotech","description":"Discover Mobility","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/mobisoftinfotech.com\/resources\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/mobisoftinfotech.com\/resources\/#\/schema\/person\/bca2da51a24299ab60cb8b27cae32db7","name":"Shubham Agarwal","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/0f49f7e61c4dcd39d24de193c609fc9713af2c8638b8d56f2c3579fc975da802?s=96&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/0f49f7e61c4dcd39d24de193c609fc9713af2c8638b8d56f2c3579fc975da802?s=96&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/0f49f7e61c4dcd39d24de193c609fc9713af2c8638b8d56f2c3579fc975da802?s=96&r=g","caption":"Shubham Agarwal"},"sameAs":["https:\/\/mobisoftinfotech.com\/"]}]}},"_links":{"self":[{"href":"https:\/\/mobisoftinfotech.com\/resources\/wp-json\/wp\/v2\/posts\/39183","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mobisoftinfotech.com\/resources\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mobisoftinfotech.com\/resources\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mobisoftinfotech.com\/resources\/wp-json\/wp\/v2\/users\/115"}],"replies":[{"embeddable":true,"href":"https:\/\/mobisoftinfotech.com\/resources\/wp-json\/wp\/v2\/comments?post=39183"}],"version-history":[{"count":55,"href":"https:\/\/mobisoftinfotech.com\/resources\/wp-json\/wp\/v2\/posts\/39183\/revisions"}],"predecessor-version":[{"id":44949,"href":"https:\/\/mobisoftinfotech.com\/resources\/wp-json\/wp\/v2\/posts\/39183\/revisions\/44949"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/mobisoftinfotech.com\/resources\/wp-json\/wp\/v2\/media\/39197"}],"wp:attachment":[{"href":"https:\/\/mobisoftinfotech.com\/resources\/wp-json\/wp\/v2\/media?parent=39183"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mobisoftinfotech.com\/resources\/wp-json\/wp\/v2\/categories?post=39183"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mobisoftinfotech.com\/resources\/wp-json\/wp\/v2\/tags?post=39183"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}