A modern, full-stack starter template powered by PayloadCMS and Next.js. Built with performance and developer experience in mind.
- Next.js 15 with App Router
 - PayloadCMS for content management
 - PostgreSQL database with Neon
 - AWS S3 for media storage
 - Authentication with Server Actions & JWT
 - Tailwind CSS & shadcn/ui for styling
 - Responsive & Mobile-First design
 - TypeScript for type safety
 - brijr/craft utilities included
 
Before you begin, ensure you have:
- Node.js (^18.20.2 or >=20.9.0)
 - pnpm package manager
 - PostgreSQL database (local or cloud)
 - AWS S3 bucket for media storage
 - Basic knowledge of TypeScript and React
 
- Clone and install dependencies:
 
git clone https://github.com/9d8dev/pay.git
cd pay
pnpm install- Set up your environment:
 
cp .env.example .env- Configure your 
.envfile with: 
# Database Configuration
DATABASE_URI=your_postgres_connection_string
PAYLOAD_SECRET=your_secure_secret_key
# S3 Configuration
S3_BUCKET=your_bucket_name
S3_REGION=your_bucket_region
S3_ACCESS_KEY_ID=your_access_key
S3_SECRET_ACCESS_KEY=your_secret_key- Start the development server:
 
pnpm dev- Visit http://localhost:3000/admin to create your first admin user
 
- 
Local PostgreSQL:
- Install PostgreSQL on your machine
 - Create a new database
 - Use the connection string: 
postgresql://username:password@localhost:5432/database 
 - 
Cloud PostgreSQL (Recommended):
- Create a database on Neon
 - Copy the connection string from your dashboard
 - Enable SSL mode with 
?sslmode=require 
 
AWS S3 Configuration (Guide)
- 
Create an S3 bucket:
- Go to AWS Console > S3
 - Create a new bucket
 - Enable public access settings
 - Configure CORS for your domain
 
 - 
Create IAM credentials:
- Create a new IAM user
 - Attach 
AmazonS3FullAccesspolicy - Save the access key and secret
 
 - 
Configure bucket policy:
 
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::your-bucket-name/*"
    }
  ]
}pay/
├── src/
│   ├── app/           # Next.js app router
│   ├── collections/   # PayloadCMS collections
│   ├── components/    # React components
│   └── lib/          # Utility functions
├── public/           # Static assets
└── package.json      # Dependencies
pnpm dev- Start development serverpnpm build- Build for productionpnpm start- Start production serverpnpm generate:types- Generate PayloadCMS types
- Push your code to GitHub
 - Import project to Vercel
 - Configure environment variables
 - Deploy!
 
- Use PostgreSQL (We recommend Neon, or any other cloud provider with PostgreSQL support)
 - Enable serverless pooling
 - Configure connection pooling
 
We welcome contributions! Please:
- Fork the repository
 - Create a feature branch
 - Submit a pull request
 
MIT 9d8
- Server-side authentication using Next.js Server Actions
 - JWT-based session management with secure HTTP-only cookies
 - Built-in login, register, and logout functionality
 - Protected routes with automatic redirects
 - TypeScript types for auth responses
 - Pre-build App Users collection at 
collections/AppUsers.ts 
- Login Form tsx import { LoginForm } from '@/components/auth/login-form'
 
export default function LoginPage() { return }
2. **Register Form**
```tsx
import { RegisterForm } from '@/components/auth/register-form'
export default function RegisterPage() {
  return <RegisterForm />
}
- Logout Button
 
import { LogoutButton } from '@/components/auth/logout-button'
export default function NavBar() {
  return <LogoutButton />
}- Protected Routes Create a layout.tsx in your protected route directory:
 
import { redirect } from 'next/navigation'
import { getUser } from '@/lib/actions/auth'
import { cookies } from 'next/headers'
export default async function ProtectedLayout({ children }) {
  const cookieStore = await cookies()
  const token = cookieStore.get('payload-token')
  if (!token) {
    redirect('/login')
  }
  const user = await getUser()
  if (!user) {
    redirect('/login')
  }
  return <>{children}</>
}The following server actions are available in @/lib/actions/auth:
loginUser({ email, password })- Authenticates user and sets sessionregisterUser({ email, password })- Creates new user and logs them inlogoutUser()- Ends session and redirects to homegetUser()- Returns current authenticated user or null
