> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-vortex-format.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Usar Laravel con ClickHouse Managed Postgres

> Conecte una aplicación Laravel a ClickHouse Managed Postgres a través de PgBouncer, ejecute migraciones y realice consultas con Eloquent mediante TLS verificado

export const BetaBadge = ({link, galaxyTrack, galaxyEvent}) => {
  if (link) {
    return <a href={link} target="_blank" rel="noopener noreferrer" className="betaBadge" onClick={galaxyTrack && galaxyEvent ? galaxyOnClick(galaxyEvent) : undefined}>
                <span>Beta</span>
            </a>;
  }
  return <a href="https://clickhouse.com/docs/reference/settings/beta-and-experimental-features#beta-features" className="betaBadge">
            <span>Funcionalidad beta</span>
        </a>;
};

<BetaBadge link="https://clickhouse.com/cloud/postgres" galaxyTrack={true} galaxyEvent="docs.managed-postgres.guides-laravel-beta" />

[Laravel](https://laravel.com/) es un framework web de PHP que incluye un ORM integrado (Eloquent), un sistema de migraciones y la herramienta de línea de comandos `artisan`. En esta guía, configurará una nueva aplicación de Laravel para conectarse a ClickHouse Managed Postgres, creará una tabla `tasks` mediante una migración y devolverá sus filas desde una ruta. Todas las conexiones usan TLS con verificación completa de certificados.

<h2 id="prerequisites">
  Requisitos previos
</h2>

* PHP 8.3 o posterior, tal como exige Laravel 13, con la extensión `pdo_pgsql`. Ejecute `php -m` y compruebe que `pdo_pgsql` aparece en la lista.
* [Composer](https://getcomposer.org/)
* Una cuenta de ClickHouse Cloud
* [`psql`](https://www.postgresql.org/download/), para crear la base de datos. También puede ejecutar la sentencia `CREATE DATABASE` en la [consola SQL](/es/integrations/connectors/sql-clients/sql-console).

<h2 id="create-service">
  Crear un servicio de ClickHouse Managed Postgres
</h2>

En la consola de ClickHouse Cloud, haga clic en **New service** y seleccione **Postgres**. La instancia estará lista en unos minutos. Consulte la [guía de inicio rápido](/es/products/managed-postgres/quickstart) para ver el proceso paso a paso.

<h2 id="connection-details">
  Obtén los detalles de conexión
</h2>

Haz clic en **Conectar** en la barra lateral izquierda de tu servicio. El cuadro modal muestra tu nombre de usuario, contraseña, servidor y puerto, e incluye un toggle **Directly** / **via PgBouncer**.

Una aplicación PHP no mantiene un grupo de conexiones entre solicitudes. De forma predeterminada, cada solicitud abre una nueva conexión a Postgres y la cierra al finalizar. En esta guía, la aplicación se conecta a través del [PgBouncer](/es/products/managed-postgres/connection#pgbouncer) integrado en el puerto `6432`, de modo que esas conexiones de corta duración compartan un pequeño conjunto de procesos backend de Postgres. Las migraciones se conectan directamente a Postgres en el puerto `5432`, ya que ejecutan DDL y pueden mantener transacciones largas.

Selecciona **via PgBouncer** para ver los detalles de la conexión agrupada. El puerto cambia a `6432` y las cadenas de conexión incluyen `sslmode=verify-full`.

En el mismo cuadro modal, haz clic en **Download CA certificate**. También puedes descargarlo desde **Settings → CA Certificate**. El certificado es exclusivo de tu instancia, lo que permite al controlador verificar que se está comunicando con tu servidor.

<h2 id="project-setup">
  Configurar el proyecto
</h2>

Cree un proyecto de Laravel:

```bash theme={null}
composer create-project laravel/laravel laravel-managed-postgres
cd laravel-managed-postgres
```

<Tip>
  **¿Va a añadirlo a una aplicación existente?**

  Omita `composer create-project`. En su proyecto, compruebe que `php -m` incluye `pdo_pgsql`; después, siga el resto de esta sección y continúe con [Configurar la conexión](#configure), donde la aplicación pasa de SQLite a Postgres. Luego, `php artisan migrate` crea sus tablas existentes en Postgres, pero no copia los datos de SQLite.
</Tip>

Mueva el certificado de CA que descargó al directorio del proyecto y cámbiele el nombre a `ca-certificate.pem`.

Cree una base de datos para la aplicación. Sustituya `<PASSWORD>` y el host por los valores del modal **Conectar**:

```bash theme={null}
psql "postgresql://postgres:<PASSWORD>@your-instance.pg.clickhouse.cloud:5432/postgres?sslmode=verify-full&sslrootcert=ca-certificate.pem" -c "CREATE DATABASE guide_laravel;"
```

```text theme={null}
CREATE DATABASE
```

<h2 id="configure">
  Configurar la conexión
</h2>

Laravel usa SQLite de forma predeterminada. Abra `.env` y sustituya la línea `DB_CONNECTION=sqlite` y las líneas `DB_` comentadas que aparecen debajo por lo siguiente:

```bash title=".env" theme={null}
DB_CONNECTION=pgsql
DB_HOST=your-instance.pg.clickhouse.cloud
DB_PORT=6432
DB_DATABASE=guide_laravel
DB_USERNAME=postgres
DB_PASSWORD=<PASSWORD>
DB_SSLMODE=verify-full
DB_SSLROOTCERT=/absolute/path/to/your-project/ca-certificate.pem
```

Use la ruta absoluta a `ca-certificate.pem`. `libpq` resuelve las rutas relativas respecto al directorio de trabajo del proceso PHP, que depende de cómo PHP ejecute su aplicación. Si su contraseña contiene espacios o `#`, escríbala entre comillas dobles. No incluya `.env` en el control de versiones.

La conexión `pgsql` predeterminada de `config/database.php` lee `DB_SSLMODE`, pero no la ruta del certificado de la CA. Abra `config/database.php` y agregue las entradas `sslrootcert` y `options` a la conexión `pgsql`:

```php title="config/database.php" theme={null}
        'pgsql' => [
            'driver' => 'pgsql',
            'url' => env('DB_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '5432'),
            'database' => env('DB_DATABASE', 'laravel'),
            'username' => env('DB_USERNAME', 'root'),
            'password' => env('DB_PASSWORD', ''),
            'charset' => env('DB_CHARSET', 'utf8'),
            'prefix' => '',
            'prefix_indexes' => true,
            'search_path' => 'public',
            'sslmode' => env('DB_SSLMODE', 'prefer'),
            'sslrootcert' => env('DB_SSLROOTCERT'),
            'options' => [
                PDO::ATTR_EMULATE_PREPARES => true,
            ],
        ],
```

Laravel añade `sslmode` y `sslrootcert` al DSN de PDO, y la extensión `pdo_pgsql` los pasa a `libpq`, que verifica la cadena de certificados y el nombre del host.

`PDO::ATTR_EMULATE_PREPARES` hace que PDO envíe cada consulta con sus valores ya vinculados, en lugar de crear una sentencia preparada del lado del servidor. Actívelo cuando se conecte a través de PgBouncer. Si `pdo_pgsql` está compilado con `libpq` 16 o anterior, como ocurre en Debian 12, PHP libera cada sentencia preparada mediante una sentencia SQL `DEALLOCATE`. PgBouncer cambia el nombre de las sentencias preparadas en el servidor, por lo que `DEALLOCATE` falla. Si esto ocurre dentro de una transacción, la transacción se aborta y la siguiente consulta falla con `current transaction is aborted`. Con `libpq` 17 o posterior, la configuración predeterminada también funciona. Ejecute `php -i | grep libpq` para comprobar su versión.

Compruebe la conexión:

```bash theme={null}
php artisan db:show
```

```text theme={null}
  PostgreSQL ................................ 18.6 (Ubuntu 18.6-1.pgdg22.04+2)  
  Connection ........................................................... pgsql  
  Database ..................................................... guide_laravel  
  Host ..................................... your-instance.pg.clickhouse.cloud  
  Port .................................................................. 6432  
  Username .......................................................... postgres  
  URL ........................................................................  
  Open Connections ........................................................ 44  
  Tables ................................................................... 0  
```

<Note>
  Sin la línea `sslrootcert`, `verify-full` falla con el error `root certificate file ".../.postgresql/root.crt" does not exist`, porque `libpq` recurre a la ubicación predeterminada de su CA. Si la CA es incorrecta, la conexión falla con `SSL error: certificate verify failed`.
</Note>

<h2 id="migrations">
  Crear un modelo y una migración
</h2>

Genere un modelo de Eloquent y una migración para una tabla `tasks`:

```bash theme={null}
php artisan make:model Task -m
```

Abra la nueva migración en `database/migrations/` (su nombre termina en `_create_tasks_table.php`) y añada las columnas `title` y `done` al método `up`:

```php title="database/migrations/xxxx_xx_xx_xxxxxx_create_tasks_table.php" theme={null}
    public function up(): void
    {
        Schema::create('tasks', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->boolean('done')->default(false);
            $table->timestamps();
        });
    }
```

Reemplace `app/Models/Task.php` para que las columnas admitan asignación masiva y `done` se devuelva como boolean:

```php title="app/Models/Task.php" theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Model;

#[Fillable(['title', 'done'])]
class Task extends Model
{
    protected function casts(): array
    {
        return [
            'done' => 'boolean',
        ];
    }
}
```

Ejecute las migraciones a través de la conexión directa. Las variables de entorno sobrescriben los valores de `.env`, así que solo necesita cambiar el puerto:

```bash theme={null}
DB_PORT=5432 php artisan migrate
```

```text theme={null}
   INFO  Preparing database.  

  Creating migration table ..................................... 289.95ms DONE

   INFO  Running migrations.  

  0001_01_01_000000_create_users_table ............................... 1s DONE
  0001_01_01_000001_create_cache_table ......................... 949.69ms DONE
  0001_01_01_000002_create_jobs_table ................................ 1s DONE
  2026_09_30_165735_create_tasks_table ......................... 240.59ms DONE
```

Además de `tasks`, esto crea las tablas `users`, `sessions`, `cache` y `jobs` que una aplicación nueva de Laravel utiliza de forma predeterminada. Laravel registra las migraciones aplicadas en la tabla `migrations` y, en ejecuciones posteriores, solo aplica las nuevas.

<h2 id="query">
  Consultar la base de datos
</h2>

Agregue algunas filas con Eloquent desde `artisan tinker`:

```bash theme={null}
php artisan tinker --execute="App\Models\Task::create(['title' => 'Create a Managed Postgres service', 'done' => true]); App\Models\Task::create(['title' => 'Connect Laravel with verify-full TLS', 'done' => true]); App\Models\Task::create(['title' => 'Ship the app']); echo App\Models\Task::count();"
```

```text theme={null}
3
```

Añada al final de `routes/web.php` una ruta que devuelva todas las tareas en formato JSON:

```php title="routes/web.php" theme={null}
Route::get('/tasks', function () {
    return App\Models\Task::orderBy('id')->get();
});
```

<Note>
  Laravel aplica las opciones de conexión `search_path`, `timezone` e `isolation_level` mediante sentencias `SET` a nivel de sesión al conectarse, y estas no se conservan entre transacciones cuando se pasa por PgBouncer. Deje estas opciones con sus valores predeterminados o, si las necesita, conéctese directamente al puerto `5432`. Las funcionalidades a nivel de sesión, como `LISTEN` y los bloqueos consultivos de sesión, tampoco funcionan a través de PgBouncer. Consulte las [preguntas frecuentes](/es/products/managed-postgres/faq#prepared-statement-errors).
</Note>

<h2 id="verify">
  Ejecutar y verificar
</h2>

Inicie el servidor de desarrollo:

```bash theme={null}
php artisan serve --port=3104
```

```text theme={null}
   INFO  Server running on [http://127.0.0.1:3104].  

  Press Ctrl+C to stop the server
```

Abre `http://localhost:3104/tasks` en tu navegador. La respuesta será similar a la siguiente:

```json theme={null}
[
  {
    "id": 1,
    "title": "Create a Managed Postgres service",
    "done": true,
    "created_at": "2026-09-30T17:10:28.000000Z",
    "updated_at": "2026-09-30T17:10:28.000000Z"
  },
  {
    "id": 2,
    "title": "Connect Laravel with verify-full TLS",
    "done": true,
    "created_at": "2026-09-30T17:10:29.000000Z",
    "updated_at": "2026-09-30T17:10:29.000000Z"
  },
  {
    "id": 3,
    "title": "Ship the app",
    "done": false,
    "created_at": "2026-09-30T17:10:29.000000Z",
    "updated_at": "2026-09-30T17:10:29.000000Z"
  }
]
```

Para ver los datos en la consola, abra **consola SQL** en la barra lateral izquierda de su servicio, expanda `guide_laravel` y, a continuación, `public`, y haga clic en la tabla `tasks`. El esquema `public` también incluye las tablas predeterminadas de Laravel, como `users`, `sessions` y `migrations`:

| id | title | done | created\_at | updated\_at |
| - | - | - | - | - |
| 1 | Create a Managed Postgres service | true | 2026-09-30 17:10:28 | 2026-09-30 17:10:28 |
| 2 | Connect Laravel with verify-full TLS | true | 2026-09-30 17:10:29 | 2026-09-30 17:10:29 |
| 3 | Ship the app | false | 2026-09-30 17:10:29 | 2026-09-30 17:10:29 |

<h2 id="next-steps">
  Próximos pasos
</h2>

* [Conexión](/es/products/managed-postgres/connection): cadenas de conexión, PgBouncer y TLS
* [Configuración](/es/products/managed-postgres/settings): parámetros de Postgres y PgBouncer, como `max_connections`
* [Réplicas de lectura](/es/products/managed-postgres/read-replicas): dirija las lecturas a una réplica mediante las [conexiones de lectura y escritura](https://laravel.com/docs/database#read-and-write-connections) de Laravel
* [Seguridad](/es/products/managed-postgres/security): listas de acceso por IP y redes privadas
