Laravel Database Configuration and .env File Best Practices

Published on November 09, 2025
Laravel Database Configuration Environment Security BestPractices

Introduction: The Foundation of Laravel Applications

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.

Understanding the .env File

What is the .env File?

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.

Key Points:

  • Never commit .env to version control
  • Each environment should have its own .env file
  • Laravel automatically loads variables from .env

Default .env Structure

# .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}"

Database Configuration Deep Dive

Configuration Files Location

  • .env - Environment-specific variables
  • config/database.php - Database configuration structure

Supported Database Drivers

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
],

Environment-Specific Configurations

Local Development Setup

# .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

Staging Environment

# .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

Production Environment

# .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

Multiple Database Connections

Configuring Multiple Connections

// 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',
    ],
],

Using Multiple Connections

// 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();

Security Best Practices

1. Never Commit .env Files

# .gitignore - Ensure these lines exist
/.env
/.env.*.local
/.env.local

2. Use Strong, Unique Passwords

# ❌ 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

3. Environment-Specific Keys

# 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...

4. Database SSL Configuration

// 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,
    ]) : [],
],

Production Deployment Checklist

Pre-Deployment Steps

  • Create production .env file
  • Generate application key
  • Set up database credentials
  • Configure appropriate permissions

Deployment Script Example

#!/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!"

Troubleshooting Common Issues

Connection Refused Error

// 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();

Permission Denied Error

# 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

Environment Variables Not Loading

// 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

Advanced Configuration Scenarios

Database URL Configuration

# 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

Read/Write Connections

// 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
],

Connection Timeouts and Limits

'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",
    ],
],

Environment Validation

Create Validation Command

<?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!');
        }
    }
}

Common Interview Questions & Answers

1. Why should .env files never be committed to version control?

.env files contain sensitive information like database credentials and API keys. Committing them creates security risks and environment configuration issues.

2. What's the difference between .env and config/database.php?

.env stores environment-specific values, while config/database.php defines the configuration structure and defaults. .env values override config/database.php settings.

3. How do you handle different database configurations for local vs production?

Use different .env files (.env.local, .env.production) with environment-specific values, and use the APP_ENV variable to control which configuration loads.

4. What's the purpose of the APP_KEY?

APP_KEY is used for encryption, hashing, and signed URLs. It should be a random, 32-character string unique to each environment.

5. How do you secure database credentials in production?

Use strong passwords, enable SSL connections, use read-only database users where possible, and regularly rotate credentials. Never hardcode credentials in config files.

6. What should you do if environment variables aren't loading?

Run php artisan config:clear, check .env file syntax, verify file permissions, and ensure the .env file is in the project root directory.

Best Practices Summary

  • ✅ Use environment-specific .env files
  • ✅ Never commit .env to version control
  • ✅ Use strong, unique passwords
  • ✅ Regularly rotate credentials
  • ✅ Validate environment configuration
  • ✅ Use SSL for database connections in production
  • ✅ Set APP_DEBUG=false in production
  • ✅ Cache configuration in production

Quick Reference Commands

# 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.