Fornece um pool de conexões PostgreSQL para o Databricks Lakebase Autoscaling com refresh automático de token OAuth.
Principais recursos:
pg.Pool padrão, compatível com qualquer biblioteca ou ORM de PostgreSQL
Refresh automático de token OAuth (tokens de 1 hora, buffer de refresh de 2 minutos)
Cache de tokens para minimizar chamadas de API
Instrumentação OpenTelemetry integrada (duração das queries, conexões do pool, refresh de token)
Logger do AppKit configurado por padrão para eventos de query e de conexão
Primeiros passos com o Lakebase
A maneira mais fácil de começar a usar o plugin do Lakebase é usar a Databricks CLI para criar um novo app do Databricks já com o AppKit e o plugin do Lakebase instalados.
Para adicionar o plugin do Lakebase ao seu projeto, execute o comando databricks apps init e selecione o plugin Lakebase no modo interativo. A CLI vai guiá-lo na escolha do projeto, da branch e do banco de dados do Lakebase.
Quando solicitado, selecione Yes para fazer o deploy do app no Databricks Apps logo após sua criação.
Uso básico
import { createApp, lakebase, server } from "@databricks/appkit";await createApp({ plugins: [server(), lakebase()],});
Acessando o pool
Após a inicialização, acesse o Lakebase por meio do objeto AppKit.lakebase:
const AppKit = await createApp({ plugins: [server(), lakebase()],});await AppKit.lakebase.query(`CREATE SCHEMA IF NOT EXISTS app`);await AppKit.lakebase.query(`CREATE TABLE IF NOT EXISTS app.orders ( id SERIAL PRIMARY KEY, user_id VARCHAR(255) NOT NULL, amount DECIMAL(10, 2) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)`);const result = await AppKit.lakebase.query( "SELECT * FROM app.orders WHERE user_id = $1", [userId],);// pg.Pool puro (para ORMs ou uso avançado)const pool = AppKit.lakebase.pool;// Objetos de configuração prontos para uso com ORMsconst ormConfig = AppKit.lakebase.getOrmConfig(); // { host, port, database, ... }const pgConfig = AppKit.lakebase.getPgConfig(); // pg.PoolConfig
Configuração
Variáveis de ambiente
As variáveis de ambiente obrigatórias são:
Variável
Descrição
LAKEBASE_ENDPOINT
Caminho do recurso do endpoint (por exemplo, projects/.../branches/.../endpoints/...)
PGHOST
Host do Lakebase (injetado automaticamente em produção pelo recurso postgres do Databricks Apps)
PGDATABASE
Nome do banco de dados (injetado automaticamente em produção pelo recurso postgres do Databricks Apps)
PGSSLMODE
Modo TLS — defina como require (injetado automaticamente em produção pelo recurso postgres do Databricks Apps)
Ao fazer o deploy no Databricks Apps com um recurso de banco de dados postgres configurado, PGHOST, PGDATABASE, PGSSLMODE, PGUSER, PGPORT e PGAPPNAME são injetados automaticamente pela plataforma. Apenas LAKEBASE_ENDPOINT precisa ser definido explicitamente:
Para desenvolvimento local, o arquivo .env é gerado automaticamente pelo databricks apps init com os valores corretos do seu projeto Lakebase.
Para a referência completa de configuração (SSL, tamanho do pool, tempos limite, logging, exemplos de ORM), consulte o README do @databricks/lakebase.
Configuração do pool
Passe um objeto pool para sobrescrever qualquer valor padrão:
await createApp({ plugins: [ lakebase({ pool: { max: 10, // Máximo de conexões do pool (padrão: 10) connectionTimeoutMillis: 5000, // Tempo limite de conexão em ms (padrão: 10000) idleTimeoutMillis: 30000, // Tempo limite de conexão ociosa em ms (padrão: 30000) }, }), ],});
On-Behalf-Of (OBO) — conexões por usuário
Quando seu app precisa de Row-Level Security (RLS) ou isolamento de dados por usuário, use asUser(req) para executar queries em um pool de conexões Lakebase específico de cada usuário. O pool de cada usuário é autenticado com a respectiva identidade Databricks, de modo que o current_user do PostgreSQL reflete o usuário real.
Pré-requisitos
Habilite a autorização de usuário no seu Databricks App com o escopo postgres. Consulte Autorização de usuário para obter as instruções de configuração. No seu databricks.yml:
resources: apps: app: user_api_scopes: - postgres
Apps criados com databricks apps init e o plugin do Lakebase já incluem isso automaticamente.
Cada usuário do app precisa de um papel do Postgres no Lakebase. Crie um com o Databricks CLI:
Outra opção é criar os papéis na UI do Lakebase, em Branch Overview → Add role.
note
Não conceda databricks_superuser a usuários OBO — superusuários ignoram o RLS. Use fine-grained grants no lugar.
Uso
Nenhuma configuração é necessária — basta chamar asUser(req):
const AppKit = await createApp({ plugins: [server(), lakebase()],});// Query do service principal (padrão — ignora o RLS como proprietário da tabela)const all = await AppKit.lakebase.query("SELECT * FROM app.orders");// Query no escopo do usuário (pool por usuário, com RLS aplicado)app.get("/api/my-orders", async (req, res) => { const result = await AppKit.lakebase .asUser(req) .query("SELECT * FROM app.orders ORDER BY created_at DESC"); res.json(result.rows);});
Quando asUser(req) é chamado:
O token e a identidade do usuário são extraídos dos cabeçalhos x-forwarded-access-token e x-forwarded-email (definidos automaticamente pelo Databricks Apps).
É criado (ou reutilizado) um pg.Pool específico para cada usuário, com as credenciais OAuth do próprio usuário.
query() e pool passam a usar o pool do usuário — o current_user no PostgreSQL reflete a identidade dele.
Exemplo de Row-Level Security
-- Como o service principal (durante o setup do app):ALTER TABLE app.orders ENABLE ROW LEVEL SECURITY;CREATE POLICY user_orders ON app.orders FOR ALL TO PUBLIC USING (owner = current_user);-- Concede acesso para que usuários OBO possam executar queriesGRANT USAGE ON SCHEMA app TO PUBLIC;GRANT SELECT, INSERT ON ALL TABLES IN SCHEMA app TO PUBLIC;
Como funciona
O pool do service principal (AppKit.lakebase.pool) é sempre criado e usado para operações DDL, seeding e queries administrativas.
Os pools por usuário são criados na primeira chamada a asUser(req) e ficam em cache por identidade de usuário. Cada pool tem seu próprio ciclo de OAuth token refresh.
As conexões ociosas dentro dos pools por usuário são fechadas automaticamente (timeout de inatividade de 30s). Objetos de pool vazios são limpos periodicamente.
No encerramento, todos os pools (SP + usuário) são fechados de forma controlada.
No modo de desenvolvimento (NODE_ENV=development), se nenhum token de usuário estiver disponível, asUser(req) recorre ao pool do SP e emite um aviso.
RLS e superusuários
Superusuários do PostgreSQL ignoram completamente a Row-Level Security. Usuários com a role databricks_superuser verão todas as linhas, independentemente das políticas de RLS. Para garantir a aplicação do RLS, use fine-grained grants em vez da role de superusuário.
Permissões do banco de dados
Ao criar o app com o recurso Lakebase seguindo o guia Primeiros passos, o service principal recebe automaticamente a permissão CONNECT_AND_CREATE no recurso postgres. Com isso, o service principal pode se conectar ao banco de dados e criar novos objetos, mas não acessar nenhum schema ou tabela já existente.
Desenvolvimento local
Para desenvolver localmente usando um banco de dados Lakebase já implantado:
Faça o deploy do app primeiro. O service principal cria o schema e as tabelas do banco de dados no primeiro deploy. Apps gerados por databricks apps init cuidam disso automaticamente — verificam se as tabelas existem na inicialização e pulam a criação caso já existam.
Conceda databricks_superuser (pule esta etapa se você for o proprietário do projeto Lakebase — nesse caso já tem acesso total):
# Cria um novo role com databricks_superuserdatabricks postgres create-role "projects/{project_id}/branches/{branch_id}" \ --json '{"spec": {"identity_type": "USER", "postgres_role": "user@example.com", "membership_roles": ["DATABRICKS_SUPERUSER"]}}'
Para conceder superuser a um role existente, use update-role:
Como alternativa, você pode gerenciar os roles na UI do Lakebase Autoscaling, na página Branch Overview do seu projeto → Add role / Edit role.
Execute localmente — sua identidade de usuário do Databricks (e-mail) é usada na autenticação OAuth. O role databricks_superuser concede acesso DML completo (leitura/escrita de dados), mas não DDL (criação de schemas ou tabelas) — é por isso que fazer o deploy primeiro faz diferença (veja a nota abaixo).
Para os demais usuários, repita o passo 2 e crie um role OAuth com databricks_superuser para cada um.
tip
A autenticação por senha do Postgres é uma alternativa mais simples, que evita a complexidade das permissões de roles OAuth. Em compensação, exige que você defina uma senha para o usuário na página Branch Overview, na UI do Lakebase Autoscaling.
Por que fazer o deploy primeiro?
Quando o app é implantado, o service principal cria os schemas e as tabelas e se torna proprietário deles. O databricks_superuser concede acesso DML completo (leitura/escrita), mas não DDL, então o desenvolvimento local só funciona depois que o schema existe.
Se você executar npm run dev antes, suas credenciais passam a ser as proprietárias do schema e o app implantado recebe permission denied. Para contornar isso, exporte os dados primeiro (pg_dump ou uma cópia temporária do schema), depois exclua o schema e faça o deploy novamente. Após o novo deploy, o service principal recria o schema na inicialização. (No PostgreSQL, a propriedade de um schema fica vinculada ao role que o criou e não pode ser reatribuída por usuários comuns.)
Permissões granulares
Na maioria dos casos de uso, databricks_superuser é suficiente. Se você precisar de grants em nível de schema, consulte a documentação oficial:
Faça o deploy e execute o app pelo menos uma vez antes de aplicar estes grants, para que o Service Principal inicialize o schema do banco de dados primeiro.
Substitua subject pelo e-mail do usuário e schema pelo nome do seu schema:
CREATE EXTENSION IF NOT EXISTS databricks_auth;DO $$DECLARE subject TEXT := 'your-subject'; -- E-mail do usuário, como name@databricks.com schema TEXT := 'your_schema'; -- Substitua 'your_schema' pelo nome do seu schemaBEGIN -- Cria a role OAuth para a identidade do Databricks PERFORM databricks_create_role(subject, 'USER'); -- Acesso à conexão e ao schema EXECUTE format('GRANT CONNECT ON DATABASE "databricks_postgres" TO %I', subject); EXECUTE format('GRANT ALL ON SCHEMA %s TO %I', schema, subject); -- Privilégios em objetos existentes EXECUTE format('GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA %s TO %I', schema, subject); EXECUTE format('GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA %s TO %I', schema, subject); EXECUTE format('GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA %s TO %I', schema, subject); EXECUTE format('GRANT ALL PRIVILEGES ON ALL PROCEDURES IN SCHEMA %s TO %I', schema, subject); -- Privilégios padrão para objetos futuros EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %s GRANT ALL ON TABLES TO %I', schema, subject); EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %s GRANT ALL ON SEQUENCES TO %I', schema, subject); EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %s GRANT ALL ON FUNCTIONS TO %I', schema, subject); EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %s GRANT ALL ON ROUTINES TO %I', schema, subject);END $$;
Databricks Developer Hub
Pronto para lançar seu próximo aplicativo baseado em agentes em minutos?