UpuaiUpuai
Bancos de dados

PostgreSQL gerenciado — PostGIS, extensões e atualizações

Crie um Postgres, ative PostGIS, pgvector e outras extensões pelo painel ou pela CLI sem reiniciar o banco, e mantenha a imagem atualizada com um clique.

O que é

Cada banco PostgreSQL gerenciado roda num cluster próprio dentro do seu ambiente. A imagem atual da plataforma já traz PostGIS 3.6, pgvector e uma lista curada de extensões: você escolhe o que ativar em cada banco, sem restart. Bancos criados antes da imagem atual recebem uma atualização de manutenção, aplicada por você quando quiser.

Ativar uma extensão é um CREATE EXTENSION no banco app — instantâneo, sem restart e sem custo para quem não usa. Só a atualização de manutenção e a troca de versão reiniciam o banco.

Criar um banco

Pelo canvas do projeto (Adicionar Serviço → Database → PostgreSQL) ou pela CLI. A versão é escolhida na criação.

Versões

PostgreSQL 15, 16, 17 ou 18, escolhida ao criar o banco. A troca para uma versão maior depois é in-place (veja Troca de versão maior).

CLI

upuai add --type database --engine postgres --name db — o alias postgres também vale em upuai template deploy (CLI v0.26.0+).

Conexão

As variáveis de conexão (DATABASE_URL e afins) são injetadas nos serviços da aplicação que referenciam o banco. O banco se chama app e o usuário da conexão é postgres, dono do banco.

Migrations

Como o usuário da conexão é dono do banco app, a migration da sua aplicação pode rodar CREATE EXTENSION IF NOT EXISTS postgis; sem passar pelo painel.

Tudo o que vale para extensões vale para o banco app, o que está no DATABASE_URL. Outros bancos que você criar no mesmo cluster continuam acessíveis por SQL com as credenciais do banco.

Extensões (PostGIS, pgvector e outras)

A lista gerenciada abaixo vem na imagem atual da plataforma. Ative, desative e atualize cada extensão no banco app.

No painel: abra o banco → aba Banco de dados → sub-aba Extensões. Cada extensão tem um switch; ativar é imediato e desativar pede confirmação. Pela CLI: upuai db extensions [enable|disable|update <nome>] (CLI v0.26.0+).

Extensões gerenciadas

Geoespacial

postgis, postgis_topology, postgis_raster, postgis_sfcgal, postgis_tiger_geocoder, address_standardizer, address_standardizer_data_us, pgrouting, earthdistance, cube

Busca e IA

vector (pgvector), pg_trgm, unaccent, fuzzystrmatch

Índices

btree_gin, btree_gist, bloom

Tipos

citext, hstore, ltree, isn, seg, intarray, uuid-ossp

Segurança

pgcrypto

Utilidades

tablefunc, postgres_fdw, dblink

Como funciona

  • Ativar roda CREATE EXTENSION ... CASCADE no banco app: as dependências entram junto (ex.: pgrouting traz postgis). É instantâneo e não reinicia o banco.
  • Desativar roda DROP EXTENSION ... RESTRICT: se uma tabela, coluna ou outra extensão depende dela, a operação é recusada e o erro lista o que depende. A plataforma nunca apaga nada em cascata.
  • Atualizar leva uma extensão instalada para a versão que a imagem atual traz (o painel mostra o botão Atualizar quando há versão nova).
  • Uma extensão marcada como indisponível (unavailable) não existe na imagem do seu banco: aplique a atualização de manutenção primeiro.
  • Com um deploy ou atualização do banco em andamento, as mudanças de extensão são recusadas até terminar.
terminal
# Listar as extensões gerenciadas e o estado de cada uma
$ upuai db extensions -s db

NAME              CATEGORY  STATUS     VERSION  DESCRIPTION
postgis           geo       enabled    3.6.4    PostGIS geometry and geography spatial types and functions
postgis_topology  geo       available  3.6.4    PostGIS topology spatial types and functions
vector            search    available  0.8.1    vector data type and ivfflat and hnsw access methods
...

# Ativar (CREATE EXTENSION ... CASCADE no banco app — sem restart)
$ upuai db extensions enable postgis -s db
✓ postgis 3.6.4 enabled

# Desativar (DROP EXTENSION ... RESTRICT — pede confirmação; -y em CI/agentes)
$ upuai db extensions disable postgis -s db -y
✗ cannot disable postgis: other objects still depend on it:
  column geo of table lojas depends on type geography
  extension postgis_topology depends on extension postgis
drop or change those objects first — the platform never drops dependent objects (no CASCADE)

# Atualizar uma extensão instalada para a versão que a imagem traz
$ upuai db extensions update postgis -s db
terminal
$ upuai db extensions -s db -o json
{
  "extensions": [
    {
      "name": "postgis",
      "category": "geo",
      "description": "PostGIS geometry and geography spatial types and functions",
      "available": true,
      "installed": true,
      "installedVersion": "3.6.4",
      "defaultVersion": "3.6.4",
      "updateAvailable": false
    }
  ]
}

Fora da lista gerenciada

  • Extensões que exigem shared_preload_libraries — pg_stat_statements e pgaudit — não são gerenciadas pelo painel nem pela CLI.
  • pg_cron não faz parte da imagem.
  • Outras extensões que existem na imagem continuam disponíveis por SQL com as credenciais do banco.

Exemplo com PostGIS

Uma tabela com coordenadas geográficas, índice espacial GiST e uma consulta por raio — o mesmo roteiro que usamos para validar a funcionalidade.

psql
CREATE EXTENSION IF NOT EXISTS postgis;  -- ou: upuai db extensions enable postgis

CREATE TABLE lojas (
  id   serial PRIMARY KEY,
  nome text,
  geo  geography(Point, 4326)
);
CREATE INDEX lojas_geo_idx ON lojas USING gist (geo);

INSERT INTO lojas (nome, geo) VALUES
  ('Savassi',        ST_GeogFromText('POINT(-43.9378 -19.9381)')),
  ('Pampulha',       ST_GeogFromText('POINT(-43.9706 -19.8512)')),
  ('Rio de Janeiro', ST_GeogFromText('POINT(-43.1729 -22.9068)'));

-- Lojas num raio de 15 km da Praça Sete (Belo Horizonte), usando o índice GiST
SELECT nome,
       round((ST_Distance(geo, ST_GeogFromText('POINT(-43.9386 -19.9191)')) / 1000)::numeric, 1) AS km
FROM lojas
WHERE ST_DWithin(geo, ST_GeogFromText('POINT(-43.9386 -19.9191)'), 15000)
ORDER BY km;

--   nome    |  km
-- ----------+-----
--  Savassi  | 2.1
--  Pampulha | 8.2
geography(Point, 4326) calcula distâncias em metros sobre o globo. O índice GiST é usado por ST_DWithin, então a consulta por raio continua rápida com milhões de pontos.

Atualização de manutenção

Leva o banco para a imagem atual da plataforma, mantendo a mesma versão maior. É assim que bancos criados antes de 2026-10-01 passam a ter PostGIS e as demais extensões gerenciadas.

  • Mesma versão maior (ex.: continua 16) — traz correções de segurança, a base atual do sistema e as extensões novas.
  • O banco reinicia e fica indisponível por cerca de 1 a 2 minutos. Os dados são preservados.
  • Se a atualização não concluir dentro da janela, a imagem anterior é restaurada automaticamente.
  • Você decide quando aplicar: o painel e a CLI avisam quando há atualização pendente.

No painel: banco → Configurações → Versão → Aplicar atualização. Pela CLI: upuai db version mostra se há atualização pendente e upuai db update --yes --wait aplica e espera terminar.

terminal
$ upuai db version -s db
  Engine   postgresql
  Version  16
  Update   available — run 'upuai db update'

$ upuai db extensions enable postgis -s db
✗ postgis is not shipped by this database's current image — apply the pending update first: upuai db update

# Mesma versão, imagem atual da plataforma. O banco reinicia (~1–2 min).
$ upuai db update -s db --yes --wait

$ upuai db update -s db --yes
✓ Database already up to date (version 16)
Num caso raro — banco que usa collations diferentes de C/POSIX (ICU ou locale libc) em índices ou no próprio banco — a troca de sistema pode mudar a ordenação de texto. A plataforma detecta isso antes de qualquer mudança e recusa a atualização com DB_MAINTENANCE_COLLATION_RISK; fale com o suporte para agendar a atualização com reindexação.

Troca de versão maior

Ex.: 16 → 17, pelo painel (Configurações → Versão) ou pela API. A troca pede confirmação.

  • Se há atualização de manutenção pendente, aplique-a primeiro — a troca de versão maior é recusada com DB_MAINTENANCE_REQUIRED até lá.
  • Um backup é feito antes de aplicar a troca.
  • A troca é offline: o banco fica indisponível durante o pg_upgrade (cerca de 2 minutos num banco pequeno no nosso teste).
  • Extensões instaladas, incluindo PostGIS, continuam funcionando na versão nova.
  • Downgrade não é suportado.

Para agentes de IA

Roteiro para um agente (Claude Code, Cursor, Codex…) que precisa de uma extensão — por exemplo, um app GeoDjango ou Rails com PostGIS.

terminal
# 1. Estado das extensões (JSON estável para scripts e agentes)
upuai db extensions -s <db> -o json

# 2a. "available": true  → ativar direto (instantâneo, sem restart)
upuai db extensions enable postgis -s <db>

# 2b. "available": false → o banco está numa imagem antiga:
#     avise o usuário que o banco reinicia por ~1–2 min, então
upuai db update -s <db> --yes --wait
upuai db extensions enable postgis -s <db>

# Alternativa: a própria migration da aplicação
#   CREATE EXTENSION IF NOT EXISTS postgis;
upuai db update reinicia o banco: avise o usuário antes. Em CI ou sem terminal, passe --yes (sem ele a CLI recusa em vez de travar esperando confirmação).

Códigos de erro

Os códigos são estáveis e iguais no painel, na API e na CLI (upuai … -o json, campo code/error).

CódigoO que significa / o que fazer
DB_EXTENSION_NOT_ALLOWEDA extensão não está na lista gerenciada. Rode upuai db extensions para ver a lista; outras extensões continuam disponíveis por SQL.
DB_EXTENSION_UNAVAILABLEA extensão não existe na imagem atual do banco. Aplique a atualização de manutenção (upuai db update) e ative de novo.
DB_EXTENSION_IN_USEAlgo depende da extensão (tabela, coluna ou outra extensão). O erro lista os dependentes: remova-os antes de desativar.
DB_OBJECT_LOCKEDUm objeto estava bloqueado por outra sessão. Tente de novo em instantes.
DB_READ_ONLYO banco está em modo somente leitura (limite de armazenamento do plano). Libere espaço ou mude de plano.
DB_OPERATION_IN_PROGRESSOutra operação (deploy, troca de versão ou atualização) está em andamento neste banco. Espere terminar.
DB_MAINTENANCE_REQUIREDTroca de versão maior pedida com atualização de manutenção pendente. Aplique a atualização primeiro.
DB_MAINTENANCE_COLLATION_RISKA atualização trocaria o sistema base e o banco usa collations cuja ordenação pode mudar. Nada foi alterado; fale com o suporte para agendar.

Perguntas frequentes

Dúvidas comuns sobre extensões e atualizações.

Ter PostGIS na imagem deixa o banco mais lento ou mais caro?

Não. A extensão só é carregada quando você a ativa e usa. Num banco que não ativou nada, ela é só um arquivo no disco.

Ativar uma extensão reinicia o banco?

Não. Ativar, desativar e atualizar extensões rodam SQL no banco app e são imediatos. Só a atualização de manutenção e a troca de versão maior reiniciam.

Posso usar PostGIS num banco criado antes de 2026-10-01?

Sim, depois da atualização de manutenção (Configurações → Versão → Aplicar atualização, ou upuai db update). O banco reinicia por 1 a 2 minutos e os dados são preservados.

Por que desativar uma extensão foi recusado?

Porque algo ainda depende dela — o erro lista o quê (ex.: uma coluna geography). A plataforma usa RESTRICT e nunca apaga dados em cascata: remova os dependentes e tente de novo.

Minha aplicação pode criar a extensão sozinha?

Pode. O usuário do DATABASE_URL é dono do banco app, então CREATE EXTENSION IF NOT EXISTS postgis; numa migration funciona — desde que a extensão exista na imagem do banco.

Dá para usar pg_cron ou pg_stat_statements?

Não pela lista gerenciada: pg_stat_statements e pgaudit exigem configuração de preload do servidor, e pg_cron não faz parte da imagem.

Recursos

Referências relacionadas.