Build a Portfolio with Laravel

Stack: PHP + Laravel + Blade

Learn Laravel by Building a Professional Portfolio Website

This comprehensive Laravel tutorial guides you through building a complete portfolio website with an admin panel. You'll learn Laravel fundamentals including Eloquent ORM, Blade templating, authentication, file uploads, and database relationships. Perfect for intermediate PHP developers ready to master Laravel's elegant MVC architecture.

What You'll Build

  • Public-facing portfolio showcase with project galleries
  • Admin dashboard for managing projects, skills, and content
  • Contact form with email notifications
  • Image upload system with optimization
  • Responsive design with Tailwind CSS

Skills You'll Master

  • Laravel Routing & Controllers: Build RESTful routes and organize application logic
  • Eloquent ORM: Create models, relationships, and database queries
  • Blade Templating: Master Laravel's powerful templating engine
  • Authentication: Implement secure login with Laravel Breeze
  • File Uploads: Handle image uploads with validation and optimization
  • Database Migrations: Version control your database schema
  • Testing with PHPUnit: Write feature tests for your portfolio

Prerequisites

  • Basic PHP knowledge (classes, functions, arrays)
  • Understanding of HTML, CSS, and basic JavaScript
  • Composer installed on your system
  • MySQL or PostgreSQL database
  • Code editor (VS Code or PHPStorm recommended)

Time Commitment: 6-8 hours total. Follow at your own pace with AI assistance. Each step includes copyable prompts for Claude or ChatGPT to help you build faster.

Why Laravel for Portfolio Development?

Laravel is the most popular PHP framework, trusted by companies worldwide for its elegant syntax and developer-friendly features. Building a portfolio with Laravel demonstrates professional-level PHP skills that employers value. Laravel's batteries-included approach means you get authentication, database tools, and testing frameworks out of the boxβ€”letting you focus on building features instead of reinventing wheels.

This tutorial teaches real-world Laravel development patterns you'll use in production applications. You'll learn to structure code properly, implement security best practices, and deploy to professional hosting platforms like Laravel Forge.

Build a Portfolio with Laravel

Laravel isn't just a PHP framework - it's the sophisticated choice for building professional portfolios that scale. With its elegant syntax, powerful ORM, and built-in authentication, you will create a portfolio that can grow from a simple showcase to a full content management system. This guide shows you how to leverage Laravel's batteries-included approach to build a portfolio that impresses both visitors and potential employers. From beautiful Blade templates to robust backend architecture, you're building something that demonstrates real engineering skill.

Laravel Portfolio Setup: Installation and Project Configuration

1

Initialize Laravel project

Laravel provides a solid foundation for building a portfolio with an admin panel. Composer handles dependency management and sets up a well-organized project structure. You can build a public-facing portfolio alongside a content management system for updating projects, all within the same framework. Laravel's conventions reduce decision fatigue.
AI Prompt
Initialize a new Laravel portfolio project using composer create-project laravel/laravel portfolio

Set up the proper folder structure for portfolio application

Configure the .env file with APP_NAME set to your portfolio name, APP_ENV=local for development, and APP_DEBUG=true

Generate application key with php artisan key:generate

Initialize git repository and create .gitignore for Laravel projects

Set up proper directory permissions for storage and bootstrap/cache directories (chmod -R 775 storage bootstrap/cache)

Plan your portfolio architecture: admin panel for content management and public-facing portfolio pages.
2

Configure PHPStorm/VS Code

PHPStorm and VS Code both work well for Laravel development. PHPStorm has built-in Laravel support, while VS Code becomes powerful with extensions like PHP Intelephense and Laravel Blade Snippets. Proper IDE configuration provides autocomplete, error detection, and debugging capabilities. Blade syntax highlighting makes templates easier to read and maintain.
AI Prompt
Configure IDE for Laravel portfolio development

For VS Code: install essential extensions: Laravel Extension Pack, PHP Intelephense, Laravel Blade Snippets, Laravel Extra Intellisense, Tailwind CSS IntelliSense

Create .vscode/settings.json with PHP formatting rules, Blade formatter settings, and file associations for .blade.php files

Set up PHP CS Fixer or Laravel Pint for code style consistency (PSR-12 standard)

Configure Xdebug for debugging

For PHPStorm: enable Laravel plugin, configure PHP interpreter, set up Blade formatting, configure database tools

Create .editorconfig for consistent formatting (4-space indent, UTF-8 charset)

Set up code snippets for common Laravel patterns.
3

Laravel Breeze, Livewire

Laravel's package ecosystem provides ready-made solutions for common portfolio needs. Laravel Breeze scaffolds authentication quickly, Livewire adds reactivity without complex JavaScript, and Spatie packages handle slugs and permissions. Intervention Image processes uploaded photos, while Filament offers a complete admin panel. These packages integrate smoothly with Laravel and save development time.
AI Prompt
Install essential packages for Laravel portfolio functionality

Install Laravel Breeze for authentication scaffolding: composer require laravel/breeze --dev, then php artisan breeze:install (choose Blade with Alpine or Livewire stack)

Install Livewire for dynamic components: composer require livewire/livewire

Add spatie/laravel-sluggable for automatic URL slug generation: composer require spatie/laravel-sluggable

Install intervention/image for image manipulation and optimization: composer require intervention/image

For admin panel, consider laravel/nova (paid) or install filament/filament (free): composer require filament/filament

Run npm install to set up frontend dependencies (Tailwind CSS, Alpine.js)

Configure each package: publish config files with php artisan vendor:publish commands as needed

Run migrations with php artisan migrate.

Database and Environment Configuration for Laravel

4

Configure MySQL/PostgreSQL

MySQL or PostgreSQL provides reliable storage for your portfolio data. Laravel's database configuration is straightforward, requiring just a few environment variables in the .env file. UTF8mb4 support handles international characters and emojis. A properly configured database makes your portfolio dynamic and content-editable through an admin interface.
AI Prompt
Configure database for portfolio content storage

In .env file, set up database connection: choose DB_CONNECTION (mysql or pgsql), set DB_HOST (localhost or 127.0.0.1), DB_PORT (3306 for MySQL, 5432 for PostgreSQL), DB_DATABASE (portfolio), DB_USERNAME, and DB_PASSWORD

Create the database using command line (mysql -u root -p, CREATE DATABASE portfolio;) or GUI tool like TablePlus, phpMyAdmin, or MySQL Workbench

Test connection with php artisan migrate:status

Configure database timezone and charset in config/database.php (utf8mb4 for full Unicode support including emojis)

Set up separate testing database in .env.testing for running tests without affecting development data.
5

Create projects, skills tables

Migrations define your database schema in version-controlled code. Design tables for projects, skills, and categories with appropriate columns like slugs for URLs, featured flags for highlighting work, and display order for organization. Many-to-many relationships between projects and skills enable filtering and categorization. Migrations are reversible, making schema changes manageable.
AI Prompt
Create database migrations for portfolio data

Run php artisan make:migration create_projects_table to create projects table with columns: id, title, slug (unique), description (text), long_description (text, nullable), tech_stack (json or separate table), project_url (nullable), github_url (nullable), image_path, featured (boolean, default false), display_order (integer), published_at (nullable timestamp), timestamps, soft_deletes

Create skills table with: id, name, category (frontend/backend/tools/soft), proficiency_level (beginner/intermediate/advanced/expert), icon_path (nullable), display_order

Create categories table if organizing projects by category: id, name, slug, description

Create project_skill pivot table for many-to-many relationship: project_id, skill_id

Add indexes on slug columns and foreign key constraints

Run php artisan migrate to create tables

Create seeders for initial data: php artisan make:seeder ProjectSeeder.
6

Set up Blade with Tailwind

Blade templates combine PHP logic with clean HTML syntax. Pair Blade with Tailwind CSS for rapid UI development using utility classes. Create reusable layout components for navigation, footer, and common elements. Alpine.js adds interactivity like mobile menus without complex JavaScript. This template system keeps your portfolio maintainable and DRY.
AI Prompt
Set up Blade template structure with Tailwind CSS styling

Create layouts/app.blade.php as main layout with <!DOCTYPE html>, head with meta tags (charset, viewport, CSRF token), @vite directive for assets, navigation header, main content area with @yield("content") or {{ $slot }}, and footer

If using Breeze, this is already created - customize it

Build layouts/guest.blade.php for public portfolio pages

Create components/nav.blade.php with responsive navigation menu: logo/name, links to Home, Projects, About, Contact sections (smooth scroll or separate pages), mobile hamburger menu using Alpine.js

Create components/footer.blade.php with social media links, copyright, optional sitemap

Set up Tailwind CSS: customize tailwind.config.js with your color scheme, fonts (add Google Fonts), and breakpoints

Create resources/css/app.css with custom styles and Tailwind directives

Build reusable Blade components for: project cards, skill badges, buttons, form inputs

Ensure responsive design with mobile-first approach

Run npm run dev to compile assets.

Building Portfolio Features: Core Functionality and Admin Panel

7

Create Project, Skill models

Eloquent models turn database tables into PHP objects with methods and relationships. Your Project model can automatically generate slugs, filter published items, and format dates. Define relationships like belongsToMany in readable PHP rather than writing SQL joins. Factories generate test data quickly. Eloquent makes database interactions intuitive and object-oriented.
AI Prompt
Create Eloquent models for portfolio data management

Generate models with php artisan make:model Project and php artisan make:model Skill

In Project model: define $fillable array (title, slug, description, long_description, tech_stack, project_url, github_url, image_path, featured, display_order, published_at), add $casts for tech_stack (array) and published_at (datetime), implement HasSlug trait from spatie/sluggable for automatic slug generation, add relationships (belongsToMany Skills, hasMany images if multiple images), create published() scope for filtering published projects, add accessor for formatted_tech_stack, implement soft deletes with SoftDeletes trait

In Skill model: define $fillable (name, category, proficiency_level, icon_path, display_order), add relationships (belongsToMany Projects), create scopes for filtering by category (scopeByCategory)

Create model factories for testing: php artisan make:factory ProjectFactory and SkillFactory

Implement model events (creating, updating) if needed for slug generation or other automation.
8

Build admin dashboard for content

An admin panel lets you manage portfolio content without editing code. Filament provides a pre-built admin interface, or you can build custom CRUD views. Features like drag-and-drop reordering, image uploads, and featured toggles make content management efficient. Rich text editors enhance project descriptions. Laravel's authentication system protects the admin area.
AI Prompt
Build an admin panel for managing portfolio content

If using Filament: install and configure with php artisan filament:install, create admin user with php artisan make:filament-user, create resources for Projects (php artisan make:filament-resource Project --generate) and Skills, customize forms with proper field types (TextInput, Textarea, Select, FileUpload, Toggle for featured), add table columns and filters

If building custom admin: create AdminController, design admin layout in resources/views/admin with sidebar navigation, create CRUD views for projects (index, create, edit), implement image upload handling with validation (max size, image types), use Storage facade for file operations, add rich text editor for descriptions (Trix, TinyMCE, or CKEditor), implement drag-and-drop reordering for display_order using Livewire or JavaScript library. Secure admin routes with auth middleware

Add authorization using Laravel policies to ensure only authenticated admins can access

Create dashboard view showing statistics: total projects, published projects, skills count

Implement bulk actions for publishing/unpublishing projects.
9

Create home, projects, about, contact

Public-facing pages showcase your work to visitors. Build a homepage with a hero section, featured projects, and skill highlights. Create a projects page with filtering and sorting capabilities. Individual project pages display full descriptions, tech stacks, and links. An About page tells your story, while a Contact form enables inquiries.
AI Prompt
Build public-facing portfolio pages with Laravel Blade

Create PortfolioController to handle routes

Build Home page (resources/views/welcome.blade.php or home.blade.php) with hero section (name, title, tagline, CTA buttons), featured projects carousel or grid (query featured projects), skills overview, call-to-action to view all projects

Create Projects page (projects/index.blade.php) displaying all published projects in grid layout with filtering/sorting options (by technology, category), use Eloquent query with eager loading: Project::with("skills")->published()->orderBy("display_order")->get()

Build individual project detail page (projects/show.blade.php) with full description, tech stack, screenshots/images, live demo and GitHub links, related projects

Create About page with bio, professional photo, comprehensive skills section organized by category (use Skill model grouped by category), timeline of experience/education, downloadable resume link

Build Contact page with contact form (name, email, message), social media links, and location

Implement form submission: create ContactController with store() method, validate input, send email using Laravel Mail with contact.blade.php email template, store messages in database (optional), show success message with flash session

Add smooth scrolling for same-page navigation links using Alpine.js or JavaScript.
10

Implement admin login

Laravel Breeze provides authentication scaffolding for securing your admin panel. Passwords are properly hashed, and middleware protects admin routes from unauthorized access. Create an initial admin user via seeder. Consider two-factor authentication for added security. Proper authentication separates public portfolio pages from admin-only content management.
AI Prompt
Implement authentication for admin panel access

If using Laravel Breeze, authentication is already scaffolded - customize it for your needs

Create admin user seeder (database/seeders/AdminSeeder.php) to create initial admin account with hashed password

Protect admin routes in routes/web.php with auth middleware: Route::middleware(["auth"])->prefix("admin")->group()

Consider adding role-based authorization: create is_admin boolean column in users migration, add middleware to check admin status, or use spatie/laravel-permission package for more robust role management. Customize login view to match portfolio design

Add logout functionality in admin header

Implement password reset functionality

Add remember me option

Consider two-factor authentication for enhanced security using laravel/fortify

Create admin profile page where admin can update their information

Add activity logging to track admin actions on portfolio content

Ensure auth redirects work correctly: after login redirect to admin dashboard, after logout redirect to homepage.
11

Set up image uploads

Laravel's Storage facade handles image uploads securely. Intervention Image can resize and optimize images automatically, creating thumbnails and converting to WebP format. The storage symlink makes uploaded files publicly accessible. Implement cleanup logic to delete images when projects are removed. Proper media management keeps your storage organized as your portfolio grows.
AI Prompt
Implement robust media management for portfolio images

Configure file storage in config/filesystems.php: set default disk to "public", ensure public disk is configured correctly

Create storage symlink with php artisan storage:link to make storage/app/public accessible via public/storage

In admin project forms, add image upload field: use HTML file input or Livewire FileUpload component

Implement upload handling in controller: validate image (required|image|mimes:jpeg,png,jpg,webp|max:5048), store with $request->file("image")->store("projects", "public"), save path to database

Use Intervention Image package to resize and optimize images on upload: create multiple sizes (thumbnail, medium, full), maintain aspect ratio, convert to WebP for better compression

Create ImageService class to handle image operations (upload, resize, delete)

Implement image deletion when project is deleted or image is replaced using Storage::delete()

On frontend, display images with proper alt tags for accessibility and SEO

Consider implementing image gallery for multiple images per project: create project_images table with project_id, image_path, order

Add drag-and-drop multi-image upload in admin. Show image previews in admin panel

Implement lazy loading for images in frontend for better performance.
15

Advanced Image Management & Galleries

You will implement advanced image management for project screenshots with intervention/image for automatic optimization - multi-image galleries with drag-and-drop reordering.
AI Prompt
Add comprehensive image management for portfolio project galleries.

Ensure intervention/image package is installed: composer require intervention/image.

Configure image settings in config/filesystems.php: create projects disk in storage/app/public/projects, configure image quality and format settings.

Create project_images migration and model: php artisan make:migration create_project_images_table with fields: project_id (foreign key), image_path, thumbnail_path, caption, display_order, is_featured.

Build ProjectImage model with relationships: belongsTo Project, implement ordering scope.

Update Project model: add hasMany ProjectImages relationship, implement featured image accessor.

Create ImageService class for image operations: upload and resize images (create multiple sizes: thumbnail 400px, medium 800px, large 1200px), maintain aspect ratio, convert to WebP with JPG fallback, optimize with quality settings, generate unique filenames using Str::uuid(), store in organized folder structure.

Implement admin image management: create image upload interface in admin/projects views using Dropzone.js or Livewire File Upload, allow multiple image uploads simultaneously, show image previews immediately after upload, implement drag-and-drop reordering using SortableJS, AJAX endpoints for ordering changes.

Build gallery display for project detail pages: create Blade component for image gallery, implement carousel/slider with Swiper or Splide, add lightbox functionality for full-size viewing using PhotoSwipe or GLightbox, show captions and image metadata.

For hero section and profile images: create separate upload endpoint for hero background images, implement image cropping interface using Cropper.js, allow position/zoom controls, generate optimized versions for different screen sizes.

Add advanced features: implement lazy loading with native loading="lazy" and IntersectionObserver fallback, serve responsive images using <picture> element with WebP and fallback formats, add image metadata: alt text (required), caption, photographer credits, implement schema.org ImageObject for SEO.

Create image cleanup service: delete old images when replaced, remove orphaned images with scheduled task (php artisan make:command CleanOrphanedImages), run weekly via Laravel Scheduler.

For large portfolios: integrate with cloud storage (S3, Cloudinary) using Laravel Storage facades, configure CDN for faster global delivery, implement image transformation on-the-fly with Cloudinary or Imgix.

Add image validation in FormRequests: validate file types (jpeg, png, gif, webp), enforce size limits (max:5120 for 5MB), check image dimensions if needed.

Testing Your Laravel Portfolio Application

12

Configure PHPUnit

PHPUnit is included with Laravel for testing your portfolio. Database factories generate test data, and in-memory SQLite keeps tests fast. The RefreshDatabase trait resets the database between tests. Laravel's testing helpers make it easy to test routes, authentication, and CRUD operations. Tests provide confidence when refactoring or adding features.
AI Prompt
Set up testing infrastructure for Laravel portfolio. PHPUnit is included by default - configure it for your needs. Review phpunit.xml configuration: ensure test database is configured (DB_CONNECTION=sqlite, DB_DATABASE=:memory: for in-memory testing), set BCRYPT_ROUNDS=4 for faster password hashing in tests, configure other test environment variables

Create TestCase extensions if needed

Set up database factories for models: php artisan make:factory ProjectFactory with realistic fake data (title using faker, description, tech stack, URLs), php artisan make:factory SkillFactory, php artisan make:factory UserFactory (may already exist)

Create seeders for test data: TestDatabaseSeeder

Add helper methods in tests/TestCase.php for common operations like creating admin user, authenticating

Install additional testing packages if desired: pestphp/pest for more expressive syntax (Laravel 10+ includes Pest by default)

Create separate test directories: tests/Feature for feature tests, tests/Unit for unit tests

Add test command shortcuts in composer.json scripts

Configure code coverage reporting if desired

Plan your testing strategy: test public portfolio pages (guests can view), test admin CRUD operations (require authentication), test authorization (only admins can access admin), test image uploads, test form validation.
13

Test homepage renders

Your first test validates that the homepage renders successfully. Check that featured projects display, navigation links work, and your name appears. When this test passes, you know the core portfolio functionality works. Tests catch regressions when you refactor or add features later.
AI Prompt
Write your first feature test for the portfolio homepage

Create tests/Feature/HomePageTest.php using php artisan make:test HomePageTest

Test that homepage returns successful response: $this->get("/")->assertStatus(200)

Test that page displays expected elements: assertSee your name/title, assertSee navigation links, assertSee hero section content

Test that featured projects are displayed: use Project factory to create featured projects, assert their titles appear on page, assert non-featured projects do not appear

Test that published projects appear but unpublished do not: create mix of published and unpublished projects, query homepage, assert only published show

Use RefreshDatabase trait to reset database for each test

Test responsive navigation: assert mobile menu exists, desktop menu exists

Test links work: assertSee with expected href attributes

Run test with php artisan test or ./vendor/bin/phpunit and verify it passes. This establishes your testing foundation and ensures homepage works as expected.
14

Test portfolio features

Test all major features including admin CRUD operations, validation, authorization, and contact form functionality. Verify that admins can manage projects, validation prevents invalid data, and unauthorized users can't access admin areas. Mock email sending to test contact forms. Tests document expected behavior and catch bugs before deployment.
AI Prompt
Write comprehensive feature tests for all portfolio functionality

Test public pages: projects index shows all published projects with pagination, project detail page displays correct project information, about page renders successfully, contact form submission works (test validation, email sending, success message)

Test admin functionality: create tests/Feature/Admin/ProjectManagementTest.php, test admin can view projects list, admin can create new project with valid data, validation prevents invalid project creation (test required fields, image validation), admin can update existing project, admin can delete project (soft delete), only authenticated users can access admin routes (guests redirected to login), test image upload creates file in storage

Test project features: test filtering projects by technology/category, test featured projects query, test project ordering by display_order

Use TestCase methods: actingAs() for authenticated requests, assertDatabaseHas/Missing for database assertions, assertRedirect for redirects, assertSessionHas for flash messages

Create helper method createAdminUser() in TestCase. Mock external services like email sending if needed

Test edge cases: empty states, invalid IDs (404 errors), permission denial (403 errors). Aim for high test coverage of critical functionality to catch regressions.

Deploying Your Laravel Portfolio to Production

16

Deploy to Laravel Forge

Laravel Forge simplifies deployment by provisioning servers, configuring SSL, and setting up automatic deployments from Git. Connect your repository, configure environment variables, and deploy. Forge handles queue workers, scheduled tasks, and database backups. Once deployed, your portfolio is live with professional infrastructure and continuous deployment.
AI Prompt
Deploy Laravel portfolio to production environment

Using Laravel Forge: create account on forge.laravel.com, connect your server provider (DigitalOcean, AWS, Linode, Vultr), provision new server (select PHP 8.2+, database, Redis), create new site on server with your domain, connect Git repository (GitHub, GitLab, Bitbucket), configure deployment script in Forge dashboard: git pull, composer install --optimize-autoloader --no-dev, npm install && npm run build, php artisan config:cache, php artisan route:cache, php artisan view:cache, php artisan migrate --force, php artisan storage:link (only needed once)

Configure environment variables in Forge: set production values for APP_ENV=production, APP_DEBUG=false, APP_URL with your domain, database credentials, mail settings

Set up SSL certificate (Forge can provision free Let's Encrypt certificate). Configure server settings: PHP version, memory limits, upload size. Set up scheduled jobs if needed (php artisan schedule:run). Configure queue workers if using queues. Set up automatic backups for database and storage. Test deployment: trigger deploy via Forge or git push to connected branch, monitor deployment log for errors. After successful deployment: test all pages load, test admin panel access, test image uploads work, verify email sending works, test contact form. Set up monitoring: enable Laravel Telescope in local/staging for debugging (not production), use error tracking service like Sentry or Flare, monitor server resources in Forge dashboard. Configure DNS to point domain to server IP. Test site on multiple devices and browsers.