A modern, feature-rich URL shortener built with Laravel, React, and TypeScript. Create short URLs with analytics, expiration dates, and a beautiful responsive interface.
This URL shortener provides a complete solution for creating and managing short URLs with a focus on user experience and functionality. Built with Laravel 12 on the backend and React with TypeScript on the frontend, it offers a modern, responsive interface with dark/light mode support.
- Backend: Laravel 12, PHP 8.2+
- Frontend: React 19, TypeScript, Tailwind CSS
- Database: SQLite (default), MySQL, PostgreSQL
- Testing: PHPUnit, Vitest
- Build Tools: Vite, Composer
- URL Shortening: Convert long URLs to short, memorable codes
- Custom Aliases: Create custom short codes for your URLs
- Click Analytics: Track clicks and view detailed statistics
- Expiration Dates: Set automatic expiration for temporary URLs
- Rate Limiting: Built-in protection against abuse
- Authentication: Secure user registration and login
- Profile Management: Update profile information and settings
- Password Reset: Secure password recovery system
- Email Verification: Optional email verification support
- YOURLS Import: Import data from existing YOURLS installations
- SQL Dump Support: Import from SQL files with automatic field mapping
- Duplicate Detection: Smart handling of existing URLs
- Transaction Safety: Safe imports with rollback capability
- Responsive Design: Works perfectly on desktop and mobile
- Dark/Light Mode: Toggle between appearance modes
- Modern UI: Clean, intuitive interface built with Radix UI
- Real-time Updates: Instant feedback and updates
- RESTful API: Programmatic access to all features
- JSON Responses: Consistent API response format
- Authentication: Secure API endpoints with user authentication
- Rate Limiting: API rate limiting for security
- PHP 8.2 or higher
- Node.js 18 or higher
- Composer
- npm or yarn
-
Install Dependencies
composer install npm install
-
Environment Setup
cp .env.example .env php artisan key:generate
-
Database Setup
php artisan migrate
-
Start Development Server
# Start all services (Laravel, Vite, Queue, Logs) composer run dev # Or start individually php artisan serve npm run dev
# Build frontend assets
npm run build
# Optimize Laravel
php artisan config:cache
php artisan route:cache
php artisan view:cacheThe application uses minimal configuration with sensible defaults:
# App Configuration
APP_NAME="Laravel URL Shortener"
APP_ENV=production
APP_DEBUG=false
APP_URL=http://localhost
# Database (SQLite by default)
DB_CONNECTION=sqlite
DB_DATABASE=database/database.sqlite
# Registration (optional)
APP_ALLOW_REGISTRATION=true
# Pagination
PAGINATION_PER_PAGE=10When importing from YOURLS, you can configure:
- Table Name: Specify custom table names with
--tableoption - User Assignment: Assign imported URLs to specific users
- Dry Run: Test imports without making changes
See YOURLS Import for more information.
> php artisan import:yourls --help
Description:
Import YOURLS data from SQL file
Usage:
import:yourls [options]
Options:
--file[=FILE] Path to SQL file to import
--user-id[=USER-ID] Default user ID to assign imported URLs to
--table[=TABLE] Table name to look for in SQL (default: auto-detect)
--dry-run Show what would be imported without actually importing
-h, --help Display help for the given command. When no command is given display help for the list command
--silent Do not output any message
-q, --quiet Only errors are displayed. All other output is suppressed
-V, --version Display this application version
--ansi|--no-ansi Force (or disable --no-ansi) ANSI output
-n, --no-interaction Do not ask any interactive question
--env[=ENV] The environment the command should run under
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug# Run all PHP tests
composer test
# Run specific test suites
php artisan test --filter=UrlControllerTest
php artisan test --filter=YourlsImportTest# Run all frontend tests
npm test
# Run tests in watch mode
npm run test:ui
# Run tests once
npm run test:runThe application includes comprehensive test coverage for:
- Feature Tests: URL creation, redirection, analytics
- Authentication Tests: Registration, login, password reset
- Import Tests: YOURLS data import functionality
- Component Tests: React component behavior
- API Tests: RESTful endpoint functionality
All API endpoints require authentication except for URL redirection.
POST /api/urls
Content-Type: application/json
{
"url": "https://example.com/very/long/url",
"short_code": "custom-alias", // optional
"expires_at": "2024-12-31T23:59:59Z" // optional
}GET /api/urls/{id}/statsPATCH /api/urls/{id}
Content-Type: application/json
{
"url": "https://new-url.com",
"expires_at": "2024-12-31T23:59:59Z"
}DELETE /api/urls/{id}GET /{short_code}Returns a 302 redirect to the original URL.
Sync files to server:
rsync -avz --exclude='public' --exclude='.git' --exclude='node_modules' --exclude='storage/logs/*' \
--exclude='storage/framework/cache/*' --exclude='storage/framework/sessions/*' \
--exclude='storage/framework/views/*' --exclude='.env' --exclude='vendor' \
--exclude='.DS_Store' --exclude='*.log' --exclude='database/*.sqlite' . \
$USERNAME@$SERVER:/home/protected/laravel-app/Simple code update (no dependency changes):
# On the server
php artisan optimize:clear
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cacheFull upgrade (after updating composer.json or package.json):
# On the server
# 1. Check public directory symlink (should be `public -> ../../public`)
# 2. Install/update dependencies
composer install --no-dev --optimize-autoloader
npm ci --production
# 3. Build frontend assets
npm run build
# 4. Adjust permissions
./scripts/adjust-nearlyfreespeech-permissions.sh
# 5. Clear and optimize -- run the steps from the simple code update section
php artisan optimize:clear
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cacheNote: For major upgrades (e.g., Laravel, Vite, React), consider running tests locally first and reviewing upgrade guides for breaking changes.
This project is licensed under the MIT License - see the LICENSE file for details.