Laravel Service Container: The Heart of Laravel Explained Simply
Understand Laravel's powerful dependency injection container.
Proper database configuration is crucial for any Laravel application. The .env file and database configuration work together to provide a secure, flexible environment for your application's data layer. Let's explore how to set this up correctly.
The .env (environment) file is where you store environment-specific configuration variables. It's the central place for sensitive information like database credentials, API keys, and application settings.
# .env
APP_NAME="TeachyLeaf Blog"
APP_ENV=local
APP_KEY=base64:your_application_key_here
APP_DEBUG=true
APP_URL=http://localhost:8000
# Database Configuration
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=teachyleaf_blog
DB_USERNAME=root
DB_PASSWORD=
# Other configurations
MAIL_MAILER=smtp
MAIL_HOST=mailpit
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=mt1
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
Laravel supports multiple database systems:
// Available connections in config/database.php
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
'pgsql' => [
'driver' => 'pgsql',
// PostgreSQL configuration
],
'sqlite' => [
'driver' => 'sqlite',
'database' => env('DB_DATABASE', database_path('database.sqlite')),
'prefix' => '',
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
],
'sqlsrv' => [
'driver' => 'sqlsrv',
// SQL Server configuration
],
# .env (Local Development)
APP_NAME="TeachyLeaf Blog - Local"
APP_ENV=local
APP_DEBUG=true
APP_URL=http://teachyleaf.test
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=teachyleaf_dev
DB_USERNAME=homestead
DB_PASSWORD=secret
# For Laravel Sail (Docker)
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=teachyleaf
DB_USERNAME=sail
DB_PASSWORD=password
# .env.staging
APP_NAME="TeachyLeaf Blog - Staging"
APP_ENV=staging
APP_DEBUG=false
APP_URL=https://staging.teachyleaf.in
DB_CONNECTION=mysql
DB_HOST=db-staging.teachyleaf.in
DB_PORT=3306
DB_DATABASE=teachyleaf_staging
DB_USERNAME=teachyleaf_staging_user
DB_PASSWORD=strong_password_here_123!
# Redis for caching
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
# .env.production
APP_NAME="TeachyLeaf Blog"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://teachyleaf.in
# Database - Production
DB_CONNECTION=mysql
DB_HOST=db-prod-cluster.cluster-1234567890.us-east-1.rds.amazonaws.com
DB_PORT=3306
DB_DATABASE=teachyleaf_prod
DB_USERNAME=teachyleaf_prod_user
DB_PASSWORD=very_strong_production_password_456!
# Read replica for read-heavy operations
DB_READ_HOST=db-prod-readonly-1.us-east-1.rds.amazonaws.com
DB_READ_USERNAME=teachyleaf_read_user
DB_READ_PASSWORD=read_only_password_789!
# Redis Cluster
REDIS_CLIENT=phpredis
REDIS_HOST=redis-cluster.teachyleaf.in
REDIS_PASSWORD=redis_production_password
REDIS_PORT=6379
# Cloud Services
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=teachyleaf-production
CLOUDFLARE_API_KEY=your_cloudflare_key
CLOUDFLARE_EMAIL=admin@teachyleaf.in
// config/database.php
'connections' => [
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
// ... other mysql options
],
'mysql_read' => [
'driver' => 'mysql',
'host' => env('DB_READ_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_READ_USERNAME', 'forge'),
'password' => env('DB_READ_PASSWORD', ''),
// ... other mysql options
],
'logging' => [
'driver' => 'mysql',
'host' => env('DB_LOG_HOST', '127.0.0.1'),
'database' => env('DB_LOG_DATABASE', 'teachyleaf_logs'),
'username' => env('DB_LOG_USERNAME', 'forge'),
'password' => env('DB_LOG_PASSWORD', ''),
// ... other mysql options
],
'analytics' => [
'driver' => 'pgsql',
'host' => env('DB_ANALYTICS_HOST'),
'database' => env('DB_ANALYTICS_DATABASE'),
'username' => env('DB_ANALYTICS_USERNAME'),
'password' => env('DB_ANALYTICS_PASSWORD'),
'charset' => 'utf8',
'prefix' => '',
'schema' => 'public',
],
],
// In your models
class User extends Model
{
protected $connection = 'mysql';
}
class ActivityLog extends Model
{
protected $connection = 'logging';
}
// In queries
$users = DB::connection('mysql_read')
->table('users')
->where('active', true)
->get();
// Dynamic connection switching
$log = new ActivityLog;
$log->setConnection('logging');
$log->message = 'User logged in';
$log->save();
# .gitignore - Ensure these lines exist
/.env
/.env.*.local
/.env.local
# ❌ DON'T
DB_PASSWORD=password
DB_PASSWORD=123456
DB_PASSWORD=teachyleaf
# ✅ DO
DB_PASSWORD=Tx8#kL9$mN2@pQ5&vR7*wS3
DB_PASSWORD=bl3G7!kP9@mQ2#vR5$wS8&zX
# Generate unique app key for each environment
php artisan key:generate
# Different keys for different environments
APP_KEY=base64:local_key_here_123...
APP_KEY=base64:staging_key_here_456...
APP_KEY=base64:production_key_here_789...
// For production databases with SSL
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST'),
// ... other config
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,
]) : [],
],
#!/bin/bash
# deploy.sh
echo "Starting deployment..."
# Copy environment file
cp .env.production .env
# Generate application key
php artisan key:generate --force
# Set proper permissions
chmod -R 755 storage
chmod -R 755 bootstrap/cache
# Cache configuration
php artisan config:cache
php artisan route:cache
php artisan view:cache
# Run migrations
php artisan migrate --force
echo "Deployment completed!"
// Check your .env values
DB_HOST=127.0.0.1 // Not 'localhost' for some systems
DB_PORT=3306 // Verify MySQL port
DB_SOCKET=/path/to/mysql.sock // If using socket
// Test connection
php artisan tinker
>>> DB::connection()->getPdo();
# Fix file permissions
chown -R www-data:www-data /path/to/your/project
chmod -R 755 storage
chmod -R 755 bootstrap/cache
# For SELinux systems
chcon -R -t httpd_sys_rw_content_t storage
// Check if .env is loaded
dd(env('APP_ENV'));
// Clear configuration cache
php artisan config:clear
php artisan cache:clear
// Check .env file syntax
# Correct
VARIABLE=value
VARIABLE="value with spaces"
# Incorrect
VARIABLE = value
VARIABLE=value # comment
# Using database URL (common in cloud platforms)
DATABASE_URL=mysql://username:password@host:port/database_name?charset=utf8mb4
# Heroku, Railway, PlanetScale example
DATABASE_URL=mysql://abc123:pass456@us-east-1.psdb.cloud:3306/teachyleaf?sslaccept=strict
// config/database.php
'mysql' => [
'driver' => 'mysql',
'read' => [
'host' => [
env('DB_READ_HOST_1', '127.0.0.1'),
env('DB_READ_HOST_2', '127.0.0.1'),
],
'username' => env('DB_READ_USERNAME', 'forge'),
'password' => env('DB_READ_PASSWORD', ''),
],
'write' => [
'host' => [
env('DB_WRITE_HOST_1', '127.0.0.1'),
],
'username' => env('DB_WRITE_USERNAME', 'forge'),
'password' => env('DB_WRITE_PASSWORD', ''),
],
// ... rest of configuration
],
'mysql' => [
'driver' => 'mysql',
// ... basic config
'options' => [
PDO::ATTR_TIMEOUT => 10,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci",
],
],
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class CheckEnvironment extends Command
{
protected $signature = 'env:check';
protected $description = 'Check environment configuration';
public function handle()
{
$this->info('Checking environment configuration...');
// Check database connection
try {
DB::connection()->getPdo();
$this->info('✅ Database connection: OK');
} catch (\Exception $e) {
$this->error('❌ Database connection failed: ' . $e->getMessage());
}
// Check required environment variables
$required = ['APP_KEY', 'DB_HOST', 'DB_DATABASE', 'DB_USERNAME'];
foreach ($required as $variable) {
if (empty(env($variable))) {
$this->error("❌ Missing required variable: $variable");
} else {
$this->info("✅ $variable: Set");
}
}
// Check debug mode in production
if (app()->environment('production') && config('app.debug')) {
$this->warn('⚠️ APP_DEBUG is true in production!');
}
}
}
.env files contain sensitive information like database credentials and API keys. Committing them creates security risks and environment configuration issues.
.env stores environment-specific values, while config/database.php defines the configuration structure and defaults. .env values override config/database.php settings.
Use different .env files (.env.local, .env.production) with environment-specific values, and use the APP_ENV variable to control which configuration loads.
APP_KEY is used for encryption, hashing, and signed URLs. It should be a random, 32-character string unique to each environment.
Use strong passwords, enable SSL connections, use read-only database users where possible, and regularly rotate credentials. Never hardcode credentials in config files.
Run php artisan config:clear, check .env file syntax, verify file permissions, and ensure the .env file is in the project root directory.
# Generate application key
php artisan key:generate
# Cache configuration (production)
php artisan config:cache
# Clear configuration cache
php artisan config:clear
# Test database connection
php artisan tinker
>>> DB::connection()->getPdo();
# Create environment file
cp .env.example .env
# View current environment
php artisan env
Now you have a comprehensive understanding of Laravel database configuration and .env file management! In our next post, we'll explore Laravel Migrations: How to Create and Modify Your Database Tables to learn how to version control your database schema.