Skip to main content

For the complete documentation index, see llms.txt

Quickstart

Two paths, depending on whether your gRPC server exposes reflection.

This page assumes pg_grpc is already installed (see Installation) and you're connected to a Postgres backend with the extension enabled:

CREATE EXTENSION IF NOT EXISTS pg_grpc;

Path 1 - Server exposes reflection

One SQL call. Schemas are fetched from the server on first use, then cached so subsequent calls to the same service skip reflection.

SELECT grpc_call(
'localhost:50051',
'auth.AuthService/GetUser',
'{"id": "42"}'::jsonb
);

Path 2 - Server does not expose reflection

Stage your .proto files, compile them, then call:

-- 1. Stage one or more .proto files
SELECT grpc_proto_stage('common.proto', $PROTO$
syntax = "proto3";
package auth;

message UserId { string id = 1; }
message User {
string id = 1;
string email = 2;
}
$PROTO$);

SELECT grpc_proto_stage('auth.proto', $PROTO$
syntax = "proto3";
import "common.proto";
package auth;

service AuthService {
rpc GetUser(UserId) returns (User);
}
$PROTO$);

-- 2. Compile every staged file at once. Failure preserves staging.
SELECT grpc_proto_compile();

-- 3. Call as if reflection had been used.
SELECT grpc_call(
'localhost:50051',
'auth.AuthService/GetUser',
'{"id": "42"}'::jsonb
);

See User-supplied protos for multi-file imports, well-known types and the full lifecycle.

One important caveat

All caches (channel pool, staged files, registered services) live inside a single Postgres backend process. They do not persist across reconnects and they are not shared between concurrent backends. (Tracking this issue here: #14: Persist staged and compiled protos across restarts)

In practice this means:

  • A new psql session starts with an empty channel cache and an empty proto registry.
  • After connection-pooler churn (PgBouncer in transaction mode, etc.), your first call on a new backend pays the reflection cost again.
  • To force a refresh inside the current session, call grpc_proto_unregister(...) or grpc_proto_unregister_all().