Laravel's DB::connection() handles PostgreSQL schema-prefixed tables through the schema configuration option in config/database.php. For other databases like MySQL, schemas are equivalent to databases and require separate connections.
PostgreSQL Schema Support:
// config/database.php
'connections' => [
'pgsql' => [
'driver' => 'pgsql',
'host' => env('DB_HOST', '127.0.0.1'),
'database' => env('DB_DATABASE', 'mydb'),
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
'schema' => 'public', // Default schema
'search_path' => 'public,other_schema', // Schema search path
],
'pgsql_analytics' => [
'driver' => 'pgsql',
'host' => env('DB_HOST', '127.0.0.1'),
'database' => env('DB_DATABASE', 'mydb'), // Same database
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
'schema' => 'analytics', // Different schema
],
];
Querying Schema-Prefixed Tables:
use Illuminate\Support\Facades\DB;
// Method 1: Use configured schema (recommended)
$users = DB::connection('pgsql')
->table('users') // Queries public.users
->get();
$events = DB::connection('pgsql_analytics')
->table('events') // Queries analytics.events
->get();
// Method 2: Explicit schema prefix in table name
$data = DB::connection('pgsql')
->table('analytics.events') // Explicit schema.table
->where('created_at', '>', now()->subDays(7))
->get();
// Method 3: Raw queries with schema
$results = DB::connection('pgsql')->select(
'SELECT * FROM analytics.events WHERE user_id = ?',
[123]
);
Eloquent Models with PostgreSQL Schemas:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
// Model using default schema (public)
class User extends Model
{
protected $connection = 'pgsql';
protected $table = 'users'; // public.users
}
// Model using specific schema
class AnalyticsEvent extends Model
{
protected $connection = 'pgsql_analytics';
protected $table = 'events'; // analytics.events (via connection config)
}
// Alternative: Schema prefix in table name
class WarehouseData extends Model
{
protected $connection = 'pgsql';
protected $table = 'warehouse.data'; // Explicit schema.table
}
// Usage
$user = User::find(1); // SELECT * FROM public.users WHERE id = 1
$event = AnalyticsEvent::create([...]); // INSERT INTO analytics.events
$data = WarehouseData::all(); // SELECT * FROM warehouse.data
MySQL "Schemas" (Actually Databases):
MySQL treats schemas as separate databases, requiring separate connections:
// config/database.php
'connections' => [
'mysql' => [
'driver' => 'mysql',
'host' => '127.0.0.1',
'database' => 'main_db', // Database 1
'username' => 'root',
'password' => 'secret',
],
'mysql_analytics' => [
'driver' => 'mysql',
'host' => '127.0.0.1',
'database' => 'analytics_db', // Database 2 (different "schema")
'username' => 'root',
'password' => 'secret',
],
];
// Query different MySQL databases
$users = DB::connection('mysql')->table('users')->get();
$events = DB::connection('mysql_analytics')->table('events')->get();
PostgreSQL Search Path:
// Set search path dynamically
DB::connection('pgsql')->statement('SET search_path TO analytics, public');
// Now queries check analytics schema first, then public
$events = DB::connection('pgsql')
->table('events') // Finds analytics.events (if exists) or public.events
->get();
Complete Multi-Schema Example:
namespace App\Services;
use Illuminate\Support\Facades\DB;
use App\Models\User;
use App\Models\AnalyticsEvent;
class SchemaService
{
public function syncUserActivity(int $userId): array
{
// Query from public schema
$user = DB::connection('pgsql')
->table('users')
->find($userId);
// Query from analytics schema (configured connection)
$events = DB::connection('pgsql_analytics')
->table('events')
->where('user_id', $userId)
->count();
// Query from warehouse schema (explicit prefix)
$aggregates = DB::connection('pgsql')
->table('warehouse.user_stats')
->where('user_id', $userId)
->first();
return [
'user' => $user,
'event_count' => $events,
'aggregates' => $aggregates,
];
}
public function createCrossSchemaReport(): void
{
DB::connection('pgsql')->transaction(function () {
// Insert into public schema
DB::table('reports')->insert([
'name' => 'User Activity Report',
'created_at' => now(),
]);
// Insert into analytics schema
DB::connection('pgsql')
->statement('INSERT INTO analytics.report_runs (report_id, run_at) VALUES (?, ?)', [
1,
now(),
]);
});
}
}
Testing Schema Access:
// Check current schema
$schema = DB::connection('pgsql')
->select('SELECT current_schema()')[0]->current_schema;
// List available schemas
$schemas = DB::connection('pgsql')
->select("SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('pg_catalog', 'information_schema')");
// Check if table exists in schema
$exists = DB::connection('pgsql')
->select(
"SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = ? AND table_name = ?)",
['analytics', 'events']
)[0]->exists;
Best Practices:
- ✅ Use
schemaconfig option for PostgreSQL connections - ✅ Create separate connections for frequently-used schemas
- ✅ Use explicit
schema.tablenotation when mixing schemas - ✅ Set
search_pathfor PostgreSQL when querying multiple schemas - ✅ For MySQL, use separate connections for different databases
- ❌ Don't hardcode schema names in queries (use config)
- ❌ Don't mix schemas without transactions (data consistency)
Version Note: PostgreSQL schema support available since Laravel 5.0+, improved configuration in Laravel 8-11 (2020-2024)