<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: kristiansnts</title>
    <description>The latest articles on Forem by kristiansnts (@kristiansnts).</description>
    <link>https://forem.com/kristiansnts</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F581517%2F0359f613-a339-4e6a-ad10-784a64e545fe.png</url>
      <title>Forem: kristiansnts</title>
      <link>https://forem.com/kristiansnts</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kristiansnts"/>
    <language>en</language>
    <item>
      <title>Deploy Laravel on Vercel for Free — Even Heavy Filament Apps</title>
      <dc:creator>kristiansnts</dc:creator>
      <pubDate>Thu, 05 Mar 2026 13:48:28 +0000</pubDate>
      <link>https://forem.com/kristiansnts/deploy-laravel-on-vercel-for-free-even-heavy-filament-apps-80</link>
      <guid>https://forem.com/kristiansnts/deploy-laravel-on-vercel-for-free-even-heavy-filament-apps-80</guid>
      <description>&lt;p&gt;How I bypassed Vercel's 250MB limit using a Go serverless proxy, compressed vendor, and a bundled PHP-FPM binary&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;I wanted to deploy a Laravel + Filament app on Vercel's free Hobby plan. Two walls hit me immediately:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;250MB size limit&lt;/strong&gt; — Vercel serverless functions have a hard 250MB unzipped cap. My &lt;code&gt;vendor/&lt;/code&gt; directory alone was over 200MB with Filament, Dompdf, and other packages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP 494 errors&lt;/strong&gt; — Using &lt;code&gt;SESSION_DRIVER=cookie&lt;/code&gt; (the only stateless option) caused "Request Header Too Large" because Filament stuffs too much data into the session cookie, exceeding Vercel's ~8KB header limit.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://github.com/juicyfx/vercel-php" rel="noopener noreferrer"&gt;vercel-php&lt;/a&gt; is a great project, but it couldn't solve the size problem for heavy apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: A Go Proxy + Compressed Vendor
&lt;/h2&gt;

&lt;p&gt;I built &lt;strong&gt;&lt;a href="https://github.com/kristiansntsdev/vercel-laravel-go" rel="noopener noreferrer"&gt;vercel-laravel-go&lt;/a&gt;&lt;/strong&gt; — a Go serverless function that wraps PHP-FPM and compresses vendor from ~200MB down to ~30MB.&lt;/p&gt;

&lt;p&gt;Here's what happens at a high level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP Request → Vercel → Go Handler → FastCGI → PHP-FPM → Laravel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Go function handles the entire PHP lifecycle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Bundles a static PHP-FPM binary&lt;/strong&gt; at build time (no runtime download needed)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extracts &lt;code&gt;vendor.tar.gz&lt;/code&gt;&lt;/strong&gt; to &lt;code&gt;/tmp/vendor&lt;/code&gt; on cold start (~30MB compressed vs 200MB+ raw)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creates symlinks&lt;/strong&gt; so Composer's autoloader resolves classes correctly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirects storage&lt;/strong&gt; to writable &lt;code&gt;/tmp/storage&lt;/code&gt; (since &lt;code&gt;/var/task&lt;/code&gt; is read-only on Vercel)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Starts PHP-FPM&lt;/strong&gt; on a Unix socket and proxies every request via FastCGI&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why Go?
&lt;/h2&gt;

&lt;p&gt;Vercel's &lt;code&gt;@vercel/go&lt;/code&gt; runtime compiles everything into a single binary. This lets me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Embed PHP-FPM and vendor.tar.gz into the function package&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;sync.Once&lt;/code&gt; for one-time cold start initialization&lt;/li&gt;
&lt;li&gt;Keep PHP-FPM alive across warm invocations (container reuse)&lt;/li&gt;
&lt;li&gt;Handle FastCGI protocol directly without extra dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Technical Deep Dive
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Vendor Compression
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;pack.sh&lt;/code&gt; script runs &lt;code&gt;composer install --no-dev --optimize-autoloader&lt;/code&gt;, then compresses &lt;code&gt;vendor/&lt;/code&gt; into a tarball, excluding tests and docs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run locally before deploy&lt;/span&gt;
bash scripts/pack.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This typically gets a 200MB+ vendor directory down to ~30MB.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build-Time Preparation
&lt;/h3&gt;

&lt;p&gt;During Vercel's build phase, &lt;code&gt;vercel-prepare.sh&lt;/code&gt; runs automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copies Laravel source files (&lt;code&gt;app/&lt;/code&gt;, &lt;code&gt;config/&lt;/code&gt;, &lt;code&gt;routes/&lt;/code&gt;, etc.) into &lt;code&gt;api/laravel/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Downloads the static PHP-FPM 8.4 binary from &lt;a href="https://github.com/crazywhalecc/static-php-cli" rel="noopener noreferrer"&gt;static-php-cli&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These get bundled with the Go function — no network calls at runtime.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cold Start Bootstrap
&lt;/h3&gt;

&lt;p&gt;When the first request hits, the Go handler:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extracts the PHP-FPM binary to &lt;code&gt;/tmp/php-fpm-bin&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Extracts &lt;code&gt;vendor.tar.gz&lt;/code&gt; to &lt;code&gt;/tmp/vendor&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Creates writable directories under &lt;code&gt;/tmp/storage/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Creates symlinks: &lt;code&gt;/tmp/app → /var/task/laravel/app&lt;/code&gt;, &lt;code&gt;/tmp/config → /var/task/laravel/config&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;Generates a PHP entry point that overrides &lt;code&gt;PackageManifest::$vendorPath&lt;/code&gt; and &lt;code&gt;storagePath&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Starts PHP-FPM and waits for the socket&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Subsequent requests on the same container skip all of this — PHP-FPM stays running.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why the Symlinks?
&lt;/h3&gt;

&lt;p&gt;This is the trickiest part. Composer's autoloader calculates &lt;code&gt;$baseDir&lt;/code&gt; as two directories up from &lt;code&gt;vendor/composer/&lt;/code&gt;. When vendor lives at &lt;code&gt;/tmp/vendor/&lt;/code&gt;, it looks for app classes at &lt;code&gt;/tmp/app/&lt;/code&gt;, &lt;code&gt;/tmp/config/&lt;/code&gt;, etc. But our source files are at &lt;code&gt;/var/task/laravel/&lt;/code&gt;. Symlinks bridge that gap.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sessions with Redis
&lt;/h3&gt;

&lt;p&gt;Cookie sessions are out (HTTP 494). File sessions are out (each invocation gets a fresh &lt;code&gt;/tmp&lt;/code&gt;). The solution: &lt;strong&gt;Upstash Redis&lt;/strong&gt; (free tier).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SESSION_DRIVER=redis
REDIS_CLIENT=predis
REDIS_URL=rediss://default:password@host:port
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;It's a one-liner install. Run this in your Laravel project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/kristiansntsdev/vercel-laravel-go/main/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Compress vendor&lt;/span&gt;
bash scripts/pack.sh

&lt;span class="c"&gt;# 2. Deploy&lt;/span&gt;
vercel deploy &lt;span class="nt"&gt;--prod&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Environment Variables
&lt;/h3&gt;

&lt;p&gt;Set these in the Vercel dashboard:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;APP_KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;php artisan key:generate --show&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DB_*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Your database credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;REDIS_URL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Upstash Redis URL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Everything else (cache paths, session config, log channel) is pre-configured in &lt;code&gt;vercel.json&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  CI/CD with GitHub Actions
&lt;/h3&gt;

&lt;p&gt;The installer also sets up &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt;. Add three secrets to your repo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;VERCEL_TOKEN&lt;/code&gt; — from vercel.com → Settings → Tokens&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VERCEL_ORG_ID&lt;/code&gt; — your Vercel user/team ID&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VERCEL_PROJECT_ID&lt;/code&gt; — from your project settings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Push to &lt;code&gt;main&lt;/code&gt; and it deploys automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cold start&lt;/td&gt;
&lt;td&gt;~2–3 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warm request&lt;/td&gt;
&lt;td&gt;Fast (PHP-FPM stays alive)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bundle size&lt;/td&gt;
&lt;td&gt;~50–80MB compressed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHP version&lt;/td&gt;
&lt;td&gt;8.4 (static binary)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Reducing Cold Starts
&lt;/h3&gt;

&lt;p&gt;Use a free external pinger to keep your container warm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cron-job.org" rel="noopener noreferrer"&gt;cron-job.org&lt;/a&gt; — ping every 5 minutes, free&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://uptimerobot.com" rel="noopener noreferrer"&gt;UptimeRobot&lt;/a&gt; — monitor every 5 minutes, free&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;Be aware of the trade-offs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No persistent filesystem&lt;/strong&gt; — use a managed database&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No queue workers&lt;/strong&gt; — run those on Railway, Fly.io, or similar&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No cron&lt;/strong&gt; — use an external scheduler or Vercel Pro cron&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;60s max request duration&lt;/strong&gt; on Hobby plan&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No static IP&lt;/strong&gt; — use a serverless-friendly database (Neon, Supabase, PlanetScale)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;If you've been stuck trying to deploy a heavy Laravel app on Vercel, give &lt;a href="https://github.com/kristiansntsdev/vercel-laravel-go" rel="noopener noreferrer"&gt;vercel-laravel-go&lt;/a&gt; a try. It works with Laravel 11 and 12, handles Filament apps without breaking a sweat, and deploys on Vercel's free tier.&lt;/p&gt;

&lt;p&gt;The key insight: compress vendor, bundle PHP-FPM, and let Go handle the plumbing.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Star the repo if it helps: &lt;a href="https://github.com/kristiansntsdev/vercel-laravel-go" rel="noopener noreferrer"&gt;github.com/kristiansntsdev/vercel-laravel-go&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vercel</category>
      <category>laravel</category>
      <category>php</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Building a Blog CMS with ShadPanel: A Step-by-Step Guide</title>
      <dc:creator>kristiansnts</dc:creator>
      <pubDate>Tue, 02 Dec 2025 16:40:55 +0000</pubDate>
      <link>https://forem.com/kristiansnts/building-a-blog-cms-with-shadpanel-a-step-by-step-guide-4dj0</link>
      <guid>https://forem.com/kristiansnts/building-a-blog-cms-with-shadpanel-a-step-by-step-guide-4dj0</guid>
      <description>&lt;p&gt;description: "Build a complete blog CMS from scratch in less than 10 minutes with ShadPanel"&lt;/p&gt;

&lt;h1&gt;
  
  
  Building a Blog CMS with ShadPanel: A Step-by-Step Guide
&lt;/h1&gt;

&lt;p&gt;I spent the last hour building a complete blog CMS from scratch. No boilerplate copy-pasting, no hours of configuration. Just straight development. Here's how I did it with ShadPanel.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We're Building
&lt;/h2&gt;

&lt;p&gt;A functional blog CMS with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User management (authors)&lt;/li&gt;
&lt;li&gt;Post creation with relationships&lt;/li&gt;
&lt;li&gt;Admin dashboard with data tables&lt;/li&gt;
&lt;li&gt;Form validation and error handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total setup time: Less than 10 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Install ShadPanel CLI
&lt;/h2&gt;

&lt;p&gt;First, install ShadPanel globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; shadpanel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then initialize your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;blog-app
shadpanel init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ShadPanel will prompt you with several questions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ What is your project name? … blog-app
✓ What do you want to install? › Full Panel with Auth
✓ Which package manager do you want to use? › pnpm
✓ Which authentication providers do you want? › Email/Password (Credentials), Google OAuth
✓ Do you want to include demo pages? (recommended for learning) … no
✓ Initialize a git repository? … no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Choose your preferences based on your needs. It handles dependency installation automatically.&lt;/p&gt;

&lt;p&gt;This scaffolds a Next.js 15 project with everything pre-configured:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication (NextAuth.js)&lt;/li&gt;
&lt;li&gt;UI components (shadcn/ui)&lt;/li&gt;
&lt;li&gt;Form builders&lt;/li&gt;
&lt;li&gt;Data tables&lt;/li&gt;
&lt;li&gt;Sidebar navigation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No need to manually install components. No configuration hell.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Database Setup
&lt;/h2&gt;

&lt;p&gt;Initialize the database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shadpanel db init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prompts you to select a database driver. I chose PostgreSQL.&lt;/p&gt;

&lt;p&gt;It automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates &lt;code&gt;.env&lt;/code&gt; with database URL&lt;/li&gt;
&lt;li&gt;Installs &lt;code&gt;@prisma/client&lt;/code&gt; and &lt;code&gt;prisma&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Generates initial Prisma schema&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using Neon (Serverless Postgres)
&lt;/h3&gt;

&lt;p&gt;I used &lt;a href="https://neon.tech" rel="noopener noreferrer"&gt;Neon&lt;/a&gt; for this project. It's serverless PostgreSQL with a generous free tier. Perfect for prototyping.&lt;/p&gt;

&lt;p&gt;Create a new project on Neon and copy the connection string.&lt;/p&gt;

&lt;p&gt;Edit &lt;code&gt;.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DATABASE_URL="postgresql://user:password@ep-xxx.region.aws.neon.tech/dbname?sslmode=require"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Alternative: Local PostgreSQL with Docker
&lt;/h3&gt;

&lt;p&gt;If you prefer local development:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; postgres &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;password &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;blog_db &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 5432:5432 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; postgres:15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DATABASE_URL="postgresql://postgres:password@localhost:5432/blog_db"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to set your NextAuth configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret-here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Generate Initial Prisma Client
&lt;/h2&gt;

&lt;p&gt;Before defining your schema, generate the Prisma client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shadpanel db generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates the initial Prisma client from the default schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Define Your Schema
&lt;/h2&gt;

&lt;p&gt;Edit &lt;code&gt;prisma/schema.prisma&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  posts     Post[]
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  authorId  Int
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  author    User     @relation(fields: [authorId], references: [id])
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two models. One relationship. Keep it simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Create Database Migration
&lt;/h2&gt;

&lt;p&gt;Create the migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shadpanel db migrate make create_user_and_post_tables
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generates a migration file in &lt;code&gt;prisma/migrations/&lt;/code&gt; based on your schema diff.&lt;/p&gt;

&lt;p&gt;Apply the migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shadpanel db migrate run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tables created. Schema synced.&lt;/p&gt;

&lt;p&gt;Now you have type-safe database access throughout your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Generate Resources with ShadPanel
&lt;/h2&gt;

&lt;p&gt;This is where ShadPanel shines. Instead of manually creating CRUD pages, use the resource generator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shadpanel resource user
shadpanel resource post
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This automatically generates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;List page with data table (&lt;code&gt;app/admin/dashboard/users/page.tsx&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Create page with form (&lt;code&gt;app/admin/dashboard/users/create/page.tsx&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Edit page with form (&lt;code&gt;app/admin/dashboard/users/edit/[id]/page.tsx&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Server actions for CRUD operations (&lt;code&gt;app/admin/dashboard/users/actions.ts&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each resource comes with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Searchable, sortable data tables&lt;/li&gt;
&lt;li&gt;Form validation&lt;/li&gt;
&lt;li&gt;Toast notifications&lt;/li&gt;
&lt;li&gt;Loading states&lt;/li&gt;
&lt;li&gt;Error handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The generator reads your Prisma schema and creates TypeScript interfaces automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Create Prisma Client Utility
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;lib/prisma.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@prisma/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;globalForPrisma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;globalThis&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PrismaClient&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;globalForPrisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PrismaClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;globalForPrisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents multiple Prisma instances during development hot reload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Fix Create and Edit Pages
&lt;/h2&gt;

&lt;p&gt;The generated forms need some adjustments for the relationship between posts and users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update Posts Create Page
&lt;/h3&gt;

&lt;p&gt;Edit &lt;code&gt;app/admin/dashboard/posts/create/page.tsx&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;Add user fetching at the top:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getUsers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/app/admin/dashboard/users/actions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchUsers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;normalized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}));&lt;/span&gt;
      &lt;span class="nf"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;normalized&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to load users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;fetchUsers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the author field in the form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormSelect&lt;/span&gt;
  &lt;span class="nx"&gt;accessor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;authorId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Author&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}))}&lt;/span&gt;
&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the submit handler to convert authorId to integer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createPost&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;authorId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// Convert to integer&lt;/span&gt;
  &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;updatedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update Posts Edit Page
&lt;/h3&gt;

&lt;p&gt;Edit &lt;code&gt;app/admin/dashboard/posts/edit/[id]/page.tsx&lt;/code&gt; with the same changes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetch users on mount&lt;/li&gt;
&lt;li&gt;Update FormSelect with user options&lt;/li&gt;
&lt;li&gt;Convert authorId to integer on submit&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Update Config Menu
&lt;/h3&gt;

&lt;p&gt;Edit &lt;code&gt;config/menu.ts&lt;/code&gt; to organize your navigation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;House&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StickyNote&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lucide-react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaultMenuConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;navMain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;My Blog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/admin/dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;House&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Posts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/admin/dashboard/posts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StickyNote&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/admin/dashboard/users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Users&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 9: Run the Application
&lt;/h2&gt;

&lt;p&gt;Start the dev server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to &lt;a href="http://localhost:3000/admin/dashboard" rel="noopener noreferrer"&gt;http://localhost:3000/admin/dashboard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You now have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complete user CRUD operations&lt;/li&gt;
&lt;li&gt;Post management with author relationships&lt;/li&gt;
&lt;li&gt;Searchable data tables&lt;/li&gt;
&lt;li&gt;Form validation&lt;/li&gt;
&lt;li&gt;Toast notifications&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Generated Code Structure
&lt;/h2&gt;

&lt;p&gt;Here's what ShadPanel creates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/admin/dashboard/
├── users/
│   ├── actions.ts          # Server actions (getUsers, createUser, etc.)
│   ├── page.tsx            # List page with data table
│   ├── create/
│   │   └── page.tsx        # Create form
│   └── edit/
│       └── [id]/
│           └── page.tsx    # Edit form
└── posts/
    ├── actions.ts
    ├── page.tsx
    ├── create/
    │   └── page.tsx
    └── edit/
        └── [id]/
            └── page.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each actions file includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;getResources()&lt;/code&gt; - Fetch all records&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getResourceById(id)&lt;/code&gt; - Fetch single record&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;createResource(data)&lt;/code&gt; - Create new record&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;updateResource(id, data)&lt;/code&gt; - Update existing record&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;deleteResource(id)&lt;/code&gt; - Delete record&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All type-safe. All using server actions. No API routes needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Commands Reference
&lt;/h2&gt;

&lt;p&gt;Here's the complete workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install ShadPanel&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; shadpanel

&lt;span class="c"&gt;# Initialize project&lt;/span&gt;
shadpanel init blog-app

&lt;span class="c"&gt;# Database setup&lt;/span&gt;
shadpanel db init
shadpanel db generate

&lt;span class="c"&gt;# After defining schema&lt;/span&gt;
shadpanel db migrate make create_user_and_post_tables
shadpanel db migrate run

&lt;span class="c"&gt;# Generate resources&lt;/span&gt;
shadpanel resource user
shadpanel resource post

&lt;span class="c"&gt;# Development&lt;/span&gt;
pnpm dev

&lt;span class="c"&gt;# Other useful commands&lt;/span&gt;
shadpanel db push              &lt;span class="c"&gt;# Quick push without migrations&lt;/span&gt;
shadpanel db studio            &lt;span class="c"&gt;# Open Prisma Studio&lt;/span&gt;
shadpanel db migrate status    &lt;span class="c"&gt;# Check migration status&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why This Workflow Works
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Resource generator eliminates boilerplate&lt;/strong&gt;: One command creates CRUD pages, forms, and server actions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server actions replace API routes&lt;/strong&gt;: Type-safe by default. No REST endpoints to maintain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prisma handles data access&lt;/strong&gt;: Define schema once. Get TypeScript types automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Form builder manages state&lt;/strong&gt;: No manual validation. No react-hook-form setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tables are powerful out of the box&lt;/strong&gt;: Sorting, filtering, pagination. Zero configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You own the code&lt;/strong&gt;: Everything lives in your project. Customize anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;shadpanel resource&lt;/code&gt; command is the killer feature. In Laravel, I'd use &lt;code&gt;php artisan make:model&lt;/code&gt; with migrations and controllers. ShadPanel brings that workflow to Next.js.&lt;/p&gt;

&lt;p&gt;The generated code is clean. No magic. Just TypeScript, React Server Components, and Prisma. You can read it, understand it, modify it.&lt;/p&gt;

&lt;p&gt;The form builder components are flexible. Use &lt;code&gt;FormInput&lt;/code&gt;, &lt;code&gt;FormTextarea&lt;/code&gt;, &lt;code&gt;FormSelect&lt;/code&gt;, &lt;code&gt;FormToggle&lt;/code&gt;, &lt;code&gt;FormMarkdownEditor&lt;/code&gt;, etc. They handle validation automatically.&lt;/p&gt;

&lt;p&gt;Tables use TanStack Table under the hood. You get all the power without the setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Fixes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Issue: Relationship Fields
&lt;/h3&gt;

&lt;p&gt;Generated forms don't automatically populate relationship fields. You need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetch related records (like we did with users)&lt;/li&gt;
&lt;li&gt;Map them to &lt;code&gt;FormSelect&lt;/code&gt; options&lt;/li&gt;
&lt;li&gt;Convert IDs to correct type (parseInt for integers)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Issue: Timestamps
&lt;/h3&gt;

&lt;p&gt;Prisma manages &lt;code&gt;createdAt&lt;/code&gt; and &lt;code&gt;updatedAt&lt;/code&gt; automatically. You don't need to set them in forms, but the generated code includes them. You can remove them from the create/update calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;I've built three admin panels with ShadPanel now. Setup time dropped from hours to minutes.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;shadpanel resource&lt;/code&gt; command is a game changer. One command generates everything you need for CRUD operations.&lt;/p&gt;

&lt;p&gt;The stack is solid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js 15 with App Router&lt;/li&gt;
&lt;li&gt;Prisma for database access&lt;/li&gt;
&lt;li&gt;TanStack Table for data tables&lt;/li&gt;
&lt;li&gt;shadcn/ui for components&lt;/li&gt;
&lt;li&gt;NextAuth.js for authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No black boxes. No vendor lock-in. You own the code.&lt;/p&gt;

&lt;p&gt;If you're building internal tools, dashboards, or CMS systems, ShadPanel is worth trying. It brings Laravel-style productivity to Next.js.&lt;/p&gt;

&lt;p&gt;The only manual work was fixing the relationship fields in the post forms. Everything else was generated.&lt;/p&gt;

&lt;p&gt;That's a complete blog CMS in under 10 minutes of actual work.&lt;/p&gt;

&lt;p&gt;referrence: &lt;br&gt;
&lt;a href="https://shadpanel-docs.vercel.app/blog/building-admin-panels" rel="noopener noreferrer"&gt;https://shadpanel-docs.vercel.app/blog/building-admin-panels&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>shadpanel</category>
      <category>blog</category>
      <category>cms</category>
    </item>
    <item>
      <title>This tool help me build next js admin only 5-minutes</title>
      <dc:creator>kristiansnts</dc:creator>
      <pubDate>Mon, 03 Nov 2025 03:41:01 +0000</pubDate>
      <link>https://forem.com/kristiansnts/this-tool-help-me-build-next-js-admin-only-5-minutes-3j43</link>
      <guid>https://forem.com/kristiansnts/this-tool-help-me-build-next-js-admin-only-5-minutes-3j43</guid>
      <description>&lt;p&gt;So, I've been building admin panels, management systems, and information systems for companies for about 2 years now. You know the struggle - you need to show clients something quickly, but setting up everything from scratch takes forever.&lt;/p&gt;

&lt;p&gt;I was using &lt;strong&gt;FilamentPHP&lt;/strong&gt; for a while. It's honestly great - super easy to set up, fast to build with, and has tons of features. But here's the annoying part: every time I needed to show a client a demo, I had to publish it to my VPS. That meant paying for hosting just to show them a few pages. It was eating into my margins.&lt;/p&gt;

&lt;p&gt;I kept thinking, "Wouldn't it be nice if we had something like Filament, but for JavaScript? Then I could just deploy demos to Vercel for free." So... I built it. Let me show you what I came up with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet ShadPanel
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ShadPanel&lt;/strong&gt; is basically a CLI tool that scaffolds a complete Next.js admin panel for you. Think of it like FilamentPHP, but for the JavaScript world.&lt;/p&gt;

&lt;p&gt;Here's what you get out of the box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🎨 &lt;strong&gt;50+ UI Components&lt;/strong&gt; - Full shadcn/ui component library&lt;/li&gt;
&lt;li&gt;📝 &lt;strong&gt;Form Builder&lt;/strong&gt; - Filament-style declarative forms (this is the good stuff)&lt;/li&gt;
&lt;li&gt;📊 &lt;strong&gt;Data Tables&lt;/strong&gt; - Sorting, filtering, pagination built right in&lt;/li&gt;
&lt;li&gt;🔐 &lt;strong&gt;Authentication&lt;/strong&gt; - NextAuth.js with Google, GitHub, or email/password&lt;/li&gt;
&lt;li&gt;🎯 &lt;strong&gt;TypeScript&lt;/strong&gt; - Everything's typed, which saves you from so many headaches&lt;/li&gt;
&lt;li&gt;🌙 &lt;strong&gt;Dark Mode&lt;/strong&gt; - Built in, because who doesn't want dark mode?&lt;/li&gt;
&lt;li&gt;📱 &lt;strong&gt;Responsive&lt;/strong&gt; - Works on mobile, tablet, desktop&lt;/li&gt;
&lt;li&gt;⚡ &lt;strong&gt;Zero Config&lt;/strong&gt; - It just works&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I built it to feel familiar if you've used Filament, but made for the Next.js/React ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's Build One - It Takes 5 Minutes
&lt;/h2&gt;

&lt;p&gt;Seriously, that's all it takes.&lt;/p&gt;

&lt;h3&gt;
  
  
  First, install it
&lt;/h3&gt;

&lt;p&gt;You can install it globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; shadpanel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or just use it with npx (no installation needed):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx shadpanel init my-admin-panel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Then run the init command
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shadpanel init my-admin-panel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI will ask you a few questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which package manager do you want? (npm, pnpm, yarn, bun)&lt;/li&gt;
&lt;li&gt;What do you want to install? (Full panel, auth + components, or just components)&lt;/li&gt;
&lt;li&gt;Authentication providers? (Google, GitHub, or email/password)&lt;/li&gt;
&lt;li&gt;Include demo pages? (I usually say yes - they're helpful)&lt;/li&gt;
&lt;li&gt;Initialize git? (Up to you)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Answer the questions, wait for it to finish, and you're done.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start it up
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-admin-panel
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;http://localhost:3000&lt;/code&gt; and boom - you've got a working admin panel with a dashboard, login page, sidebar navigation... the whole thing. That's literally it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Actually Get
&lt;/h2&gt;

&lt;p&gt;After running the init command, you'll have:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Complete admin panel structure&lt;/strong&gt; - Authentication, dashboard, the works&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;50+ UI components&lt;/strong&gt; - All the shadcn/ui components, ready to use&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Form builder&lt;/strong&gt; - Build forms without the headache&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Data tables&lt;/strong&gt; - Full-featured tables with zero config&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Dark mode&lt;/strong&gt; - Toggle it on/off, it just works&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;TypeScript&lt;/strong&gt; - Everything's typed from the start&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Tailwind CSS v4&lt;/strong&gt; - Latest version, already configured  &lt;/p&gt;

&lt;p&gt;All set up and working in about 30 seconds. No joke.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Form Builder - This is the Good Part
&lt;/h2&gt;

&lt;p&gt;The form builder is inspired by FilamentPHP. You just describe what you want, and it handles all the messy stuff - validation, styling, state management. No more writing &lt;code&gt;useState&lt;/code&gt; for every field or handling validation errors manually.&lt;/p&gt;

&lt;p&gt;Here's what it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FormInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FormSelect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FormSection&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/ui&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/ui&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;
      &lt;span class="na"&gt;initialValues&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormSection&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"User Information"&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Enter user details"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormInput&lt;/span&gt; &lt;span class="na"&gt;accessor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormInput&lt;/span&gt; &lt;span class="na"&gt;accessor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Email"&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormSelect&lt;/span&gt;
          &lt;span class="na"&gt;accessor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"role"&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Role"&lt;/span&gt;
          &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;FormSection&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Validation happens automatically, styling is consistent, state is managed for you. It's honestly a game changer.&lt;/p&gt;

&lt;p&gt;You've got &lt;code&gt;FormInput&lt;/code&gt;, &lt;code&gt;FormTextarea&lt;/code&gt;, &lt;code&gt;FormSelect&lt;/code&gt;, &lt;code&gt;FormCheckbox&lt;/code&gt;, &lt;code&gt;FormToggle&lt;/code&gt;, &lt;code&gt;FormDatePicker&lt;/code&gt;, &lt;code&gt;FormFileUpload&lt;/code&gt;, and more. Plus layout components like &lt;code&gt;FormSection&lt;/code&gt; and &lt;code&gt;FormGrid&lt;/code&gt; to organize everything nicely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Tables - Also Pretty Nice
&lt;/h2&gt;

&lt;p&gt;Tables are dead simple too. Just pass in your data and tell it what columns you want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TableTextColumn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TableActionsColumn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TableAction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/ui&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Edit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Trash&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lucide-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UsersTable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TableTextColumn&lt;/span&gt; &lt;span class="na"&gt;accessor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt; &lt;span class="na"&gt;sortable&lt;/span&gt; &lt;span class="na"&gt;searchable&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TableTextColumn&lt;/span&gt; &lt;span class="na"&gt;accessor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Email"&lt;/span&gt; &lt;span class="na"&gt;searchable&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TableTextColumn&lt;/span&gt; &lt;span class="na"&gt;accessor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"role"&lt;/span&gt; &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Role"&lt;/span&gt; &lt;span class="na"&gt;sortable&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TableActionsColumn&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TableAction&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Edit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Edit"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleEdit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TableAction&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Trash&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Delete"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleDelete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;TableActionsColumn&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. You get sorting, searching, filtering, pagination, row selection, bulk actions... all without writing a single line of table logic. It's wild how much time this saves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database Stuff (If You Need It)
&lt;/h2&gt;

&lt;p&gt;Need a database? There's a CLI command for that too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shadpanel db init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It'll ask you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which database do you want? (MySQL, PostgreSQL, SQLite, or MongoDB)&lt;/li&gt;
&lt;li&gt;Then it creates your &lt;code&gt;.env&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Sets up Prisma for you&lt;/li&gt;
&lt;li&gt;Installs all the packages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After that, you just define your models and run migrations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shadpanel db migrate make create_users
shadpanel db migrate run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's optional though - only set it up if you actually need it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Resource Generator - This Blew My Mind
&lt;/h2&gt;

&lt;p&gt;Okay, so here's where it gets really cool. Once you have Prisma set up, you can generate entire CRUD pages from your models with a single command. Like, the whole thing - list view, create form, edit form, delete actions... everything.&lt;/p&gt;

&lt;p&gt;Let's say you have a &lt;code&gt;Post&lt;/code&gt; model in your Prisma schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean  @default(false)
  createdAt DateTime @default(now())
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shadpanel resource posts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or the short version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shadpanel r posts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. One command and you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;List page&lt;/strong&gt; - Data table with all your posts, searchable, sortable&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Create page&lt;/strong&gt; - Form to create new posts&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Edit page&lt;/strong&gt; - Form to update existing posts&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Delete functionality&lt;/strong&gt; - Built right into the table&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Server actions&lt;/strong&gt; - All the backend CRUD operations&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Menu integration&lt;/strong&gt; - Automatically added to your sidebar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the code is generated for you. The forms use the Form Builder, the tables use the Data Table component, everything is typed and ready to go. You just customize it if you need to.&lt;/p&gt;

&lt;p&gt;This is honestly the feature that saves the most time. I can go from "I need a posts management page" to "here's your working CRUD interface" in like 30 seconds. It's wild.&lt;/p&gt;

&lt;p&gt;The resource generator is smart too - it detects field types and uses the right form inputs (text for strings, checkboxes for booleans, date pickers for DateTime fields, etc.). Relations are automatically excluded from forms (which makes sense).&lt;/p&gt;

&lt;h2&gt;
  
  
  It's Flexible - You Own the Code
&lt;/h2&gt;

&lt;p&gt;One thing I really wanted to get right is flexibility. ShadPanel isn't some locked-down framework - it's just Next.js code that gets generated for you. You can change anything.&lt;/p&gt;

&lt;p&gt;Want to customize a component? Go ahead, change the className, add your own styles, modify the logic - it's your code. The components are just starting points, not locked templates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Generated code, but you can change it however you want&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormInput&lt;/span&gt; 
  &lt;span class="na"&gt;accessor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; 
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt; 
  &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"my-custom-class"&lt;/span&gt;  &lt;span class="c1"&gt;// Add your own classes&lt;/span&gt;
  &lt;span class="na"&gt;required&lt;/span&gt; 
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Need to change how forms work? Modify the Form component. Want to customize the data table? It's all right there in your &lt;code&gt;components/ui&lt;/code&gt; folder. Everything follows Next.js conventions, so if you know Next.js, you know how to customize everything.&lt;/p&gt;

&lt;p&gt;The only opinionated part is the built-in components themselves - they have sensible defaults. But once they're in your project, they're just components in your codebase. Change them, extend them, replace them - whatever you need.&lt;/p&gt;

&lt;p&gt;It's like how Next.js works - opinionated about the file structure and conventions, but you control everything else. That's exactly how I wanted ShadPanel to feel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying to Vercel - This is Why I Built It
&lt;/h2&gt;

&lt;p&gt;Since it's a Next.js app, deploying to Vercel is trivial:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push your code to GitHub&lt;/li&gt;
&lt;li&gt;Import it in Vercel&lt;/li&gt;
&lt;li&gt;Add your environment variables (if you're using auth or database)&lt;/li&gt;
&lt;li&gt;Hit deploy&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. No VPS, no server management, and it's free. This is the whole reason I built this thing - I can spin up a demo, send the client a link, and not worry about server costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Used It Last Week
&lt;/h2&gt;

&lt;p&gt;Last week, a client asked me to show them what an admin panel would look like. I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shadpanel init client-admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Selected Google OAuth, added demo pages, and within minutes I had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A working login with Google&lt;/li&gt;
&lt;li&gt;A dashboard&lt;/li&gt;
&lt;li&gt;A user management form&lt;/li&gt;
&lt;li&gt;A users table with data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I added a couple of custom fields, pushed to GitHub, deployed to Vercel, and sent them the link. They could see it the same day.&lt;/p&gt;

&lt;p&gt;No setting up servers, no configuring databases on a VPS - just Next.js deploying to Vercel. It's beautiful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;Look, I just wanted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt; - Set up in minutes, not hours&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost-effective&lt;/strong&gt; - Free demos on Vercel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Familiar&lt;/strong&gt; - Feels like Filament, but for JavaScript&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern&lt;/strong&gt; - Next.js, TypeScript, Tailwind&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible&lt;/strong&gt; - Works standalone or merge into existing projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And honestly, it does all of that. I'm pretty happy with how it turned out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Out
&lt;/h2&gt;

&lt;p&gt;If you're building admin panels or internal tools, give it a shot. Setup takes like 5 minutes, and you'll have something working immediately.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📚 &lt;strong&gt;Documentation&lt;/strong&gt;: &lt;a href="https://shadpanel-docs.vercel.app" rel="noopener noreferrer"&gt;https://shadpanel-docs.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/kristiansnts/shadpanel" rel="noopener noreferrer"&gt;https://github.com/kristiansnts/shadpanel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📦 &lt;strong&gt;NPM&lt;/strong&gt;: Just run &lt;code&gt;npm install -g shadpanel&lt;/code&gt; or &lt;code&gt;npx shadpanel init&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;That's it. If you try it out, let me know what you think. Happy building!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tags&lt;/strong&gt;: &lt;code&gt;#nextjs&lt;/code&gt; &lt;code&gt;#react&lt;/code&gt; &lt;code&gt;#typescript&lt;/code&gt; &lt;code&gt;#adminpanel&lt;/code&gt; &lt;code&gt;#shadcn&lt;/code&gt; &lt;code&gt;#webdev&lt;/code&gt; &lt;code&gt;#javascript&lt;/code&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
