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

# Use o Laravel com o ClickHouse Managed Postgres

> Conecte uma aplicação Laravel ao ClickHouse Managed Postgres via PgBouncer, execute migrações e faça consultas com o Eloquent usando 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>Recurso beta</span>
        </a>;
};

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

O [Laravel](https://laravel.com/) é um framework web em PHP com um ORM integrado (Eloquent), um sistema de migrações e a ferramenta de linha de comando `artisan`. Neste guia, você vai apontar um novo aplicativo Laravel para o ClickHouse Managed Postgres, criar uma tabela `tasks` com uma migração e servir as linhas dela a partir de uma rota. Todas as conexões usam TLS com verificação completa de certificados.

<h2 id="prerequisites">
  Pré-requisitos
</h2>

* PHP 8.3 ou superior, conforme exigido pelo Laravel 13, com a extensão `pdo_pgsql`. Execute `php -m` e verifique se `pdo_pgsql` aparece na lista.
* [Composer](https://getcomposer.org/)
* Uma conta do ClickHouse Cloud
* [`psql`](https://www.postgresql.org/download/), para criar o banco de dados. Você também pode executar a instrução `CREATE DATABASE` no [SQL Console](/pt-BR/integrations/connectors/sql-clients/sql-console).

<h2 id="create-service">
  Criar um serviço ClickHouse Managed Postgres
</h2>

No console do ClickHouse Cloud, clique em **New service** e selecione **Postgres**. A instância fica pronta em poucos minutos. Para um passo a passo, consulte o [guia de início rápido](/pt-BR/products/managed-postgres/quickstart).

<h2 id="connection-details">
  Obtenha os detalhes de conexão
</h2>

Clique em **Connect** na barra lateral esquerda do seu serviço. O modal exibe o nome de usuário, a senha, o servidor e a porta, além de uma chave **Directly** / **via PgBouncer**.

Uma aplicação PHP não mantém um pool de conexões entre requisições. Por padrão, cada requisição abre uma nova conexão com o Postgres e a encerra ao final da requisição. Neste guia, a aplicação se conecta pelo [PgBouncer](/pt-BR/products/managed-postgres/connection#pgbouncer) incluído no serviço, na porta `6432`, para que essas conexões de curta duração compartilhem um pequeno conjunto de backends do Postgres. As migrações se conectam diretamente ao Postgres na porta `5432`, pois executam DDL e podem manter transações longas.

Selecione **via PgBouncer** para ver os detalhes da conexão com pooling. A porta muda para `6432`, e as strings de conexão passam a incluir `sslmode=verify-full`.

No mesmo modal, clique em **Download CA certificate**. Você também pode baixá-lo em **Settings → CA Certificate**. O certificado é exclusivo da sua instância, o que permite ao driver usá-lo para verificar se está se comunicando com o seu servidor.

<h2 id="project-setup">
  Configure o projeto
</h2>

Crie um projeto Laravel:

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

<Tip>
  **Vai adicionar a um app existente?**

  Pule o `composer create-project`. No seu projeto, verifique se `php -m` lista `pdo_pgsql`, depois siga o restante desta seção e continue em [Configurar a conexão](#configure), que muda o app de SQLite para Postgres. Em seguida, `php artisan migrate` cria suas tabelas existentes no Postgres, mas não copia os dados do SQLite.
</Tip>

Mova o certificado de CA que você baixou para o diretório do projeto e renomeie-o para `ca-certificate.pem`.

Crie um banco de dados para o app. Substitua `<PASSWORD>` e o host pelos valores do modal **Connect**:

```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">
  Configure a conexão
</h2>

Por padrão, o Laravel usa SQLite. Abra o arquivo `.env` e substitua a linha `DB_CONNECTION=sqlite` e as linhas `DB_` comentadas logo abaixo dela por:

```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 o caminho absoluto para `ca-certificate.pem`. O `libpq` resolve caminhos relativos com base no diretório de trabalho do processo PHP, que varia conforme a forma como o PHP executa sua aplicação. Se a sua senha contiver espaços ou `#`, coloque-a entre aspas duplas. Mantenha o `.env` fora do controle de versão.

A conexão `pgsql` padrão em `config/database.php` lê `DB_SSLMODE`, mas não o caminho do certificado da CA. Abra `config/database.php` e adicione as entradas `sslrootcert` e `options` à conexão `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,
            ],
        ],
```

O Laravel adiciona `sslmode` e `sslrootcert` ao DSN do PDO, e a extensão `pdo_pgsql` os repassa à `libpq`, que verifica a cadeia de certificados e o hostname.

`PDO::ATTR_EMULATE_PREPARES` faz com que o PDO envie cada consulta com os valores já vinculados, em vez de criar um prepared statement no lado do servidor. Ative essa opção ao se conectar pelo PgBouncer. Quando o `pdo_pgsql` é compilado com a `libpq` 16 ou anterior, como no Debian 12, o PHP libera cada prepared statement com uma instrução SQL `DEALLOCATE`. Como o PgBouncer renomeia os prepared statements no servidor, o `DEALLOCATE` falha. Dentro de uma transação, isso aborta a transação, e a consulta seguinte falha com `current transaction is aborted`. Com a `libpq` 17 ou posterior, as configurações padrão também funcionam. Execute `php -i | grep libpq` para ver a sua versão.

Verifique a conexão:

```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>
  Sem a linha `sslrootcert`, o `verify-full` falha com `root certificate file ".../.postgresql/root.crt" does not exist`, porque o `libpq` recorre ao seu local padrão de CA. Com a CA errada, a conexão falha com `SSL error: certificate verify failed`.
</Note>

<h2 id="migrations">
  Crie um model e uma migração
</h2>

Gere um model Eloquent e uma migração para uma tabela `tasks`:

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

Abra a nova migração em `database/migrations/` (o nome do arquivo termina em `_create_tasks_table.php`) e adicione as colunas `title` e `done` ao 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();
        });
    }
```

Substitua o conteúdo de `app/Models/Task.php` para que as colunas possam ser atribuídas em massa e `done` seja retornado como booleano:

```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',
        ];
    }
}
```

Execute as migrações pela conexão direta. Uma variável de ambiente tem precedência sobre o valor definido em `.env`, então basta alterar a porta:

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

Além de `tasks`, esse comando cria as tabelas `users`, `sessions`, `cache` e `jobs` que uma nova aplicação Laravel usa por padrão. O Laravel registra as migrações já aplicadas na tabela `migrations` e, nas execuções seguintes, executa apenas as novas.

<h2 id="query">
  Consultar o banco de dados
</h2>

Adicione algumas linhas usando o Eloquent no `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
```

Adicione ao final de `routes/web.php` uma rota que retorne todas as tarefas em JSON:

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

<Note>
  O Laravel aplica as opções de conexão `search_path`, `timezone` e `isolation_level` por meio de instruções `SET` em nível de sessão ao se conectar, e essas configurações não são preservadas entre transações quando se usa o PgBouncer. Mantenha essas opções com os valores padrão ou, se precisar delas, conecte-se diretamente pela porta `5432`. Recursos em nível de sessão, como `LISTEN` e advisory locks de sessão, também não funcionam através do PgBouncer. Consulte o [FAQ](/pt-BR/products/managed-postgres/faq#prepared-statement-errors).
</Note>

<h2 id="verify">
  Executar e verificar
</h2>

Inicie o servidor de desenvolvimento:

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

Abra `http://localhost:3104/tasks` no navegador. A resposta será semelhante a esta:

```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 os dados no console, abra o **SQL Console** na barra lateral esquerda do seu serviço, expanda `guide_laravel` e depois `public` e clique na tabela `tasks`. O schema `public` também lista as tabelas padrão do Laravel, como `users`, `sessions` e `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 passos
</h2>

* [Conexão](/pt-BR/products/managed-postgres/connection): strings de conexão, PgBouncer e TLS
* [Configurações](/pt-BR/products/managed-postgres/settings): parâmetros do Postgres e do PgBouncer, como `max_connections`
* [Réplicas de leitura](/pt-BR/products/managed-postgres/read-replicas): direcione leituras para uma réplica com as [conexões de leitura e escrita](https://laravel.com/docs/database#read-and-write-connections) do Laravel
* [Segurança](/pt-BR/products/managed-postgres/security): listas de acesso por IP e rede privada
