grpc
$
npx mdskill add TerminalSkills/skills/grpcBuild high-performance RPC services with gRPC and Protocol Buffers.
- Creates microservices communication and real-time streaming APIs.
- Integrates HTTP/2 transport and Protocol Buffers serialization.
- Generates client stubs in Node.js, Python, or Go environments.
- Delivers production-ready code with interceptors and health checks.
SKILL.md
.github/skills/grpcView on GitHub ↗
---
name: grpc
description: >-
Build high-performance RPC services with gRPC and Protocol Buffers. Use when a
user asks to create gRPC services, define protobuf schemas, implement
streaming RPCs, build microservice communication, set up service-to-service
calls, implement bidirectional streaming, add interceptors/middleware to gRPC,
generate client stubs, handle gRPC errors, implement health checks, configure
load balancing, or build gRPC-Web for browser clients. Covers unary,
server/client/bidirectional streaming, interceptors, deadlines, metadata,
reflection, and production patterns.
license: Apache-2.0
compatibility: 'Node.js 18+, Python 3.9+, or Go 1.21+ (grpc, protobuf)'
metadata:
author: terminal-skills
version: 1.0.0
category: development
tags:
- grpc
- rpc
- protobuf
- microservices
- streaming
---
# gRPC
## Overview
Build high-performance, strongly-typed RPC services using gRPC and Protocol Buffers. gRPC uses HTTP/2 for transport, protobuf for serialization (10x smaller than JSON, 5-10x faster parsing), and generates client/server code in 12+ languages. Ideal for microservice communication, real-time streaming, and performance-critical APIs.
## Instructions
### Step 1: Install Tools
```bash
# Protocol Buffer Compiler
brew install protobuf # macOS
apt install -y protobuf-compiler # Ubuntu/Debian
# Node.js
npm install @grpc/grpc-js @grpc/proto-loader
# Python
pip install grpcio grpcio-tools grpcio-reflection grpcio-health-checking
# Go
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
```
### Step 2: Define Protocol Buffers
```protobuf
// proto/user_service.proto
syntax = "proto3";
package userservice.v1;
import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
service UserService {
rpc GetUser(GetUserRequest) returns (User);
rpc CreateUser(CreateUserRequest) returns (User);
rpc UpdateUser(UpdateUserRequest) returns (User);
rpc DeleteUser(DeleteUserRequest) returns (google.protobuf.Empty);
rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
rpc WatchUser(WatchUserRequest) returns (stream UserEvent); // Server streaming
rpc BatchCreateUsers(stream CreateUserRequest) returns (BatchCreateUsersResponse); // Client streaming
rpc Chat(stream ChatMessage) returns (stream ChatMessage); // Bidirectional
}
message User {
string id = 1;
string email = 2;
string name = 3;
Role role = 5;
google.protobuf.Timestamp created_at = 6;
}
enum Role { ROLE_UNSPECIFIED = 0; ROLE_USER = 1; ROLE_ADMIN = 2; }
message GetUserRequest { string id = 1; }
message CreateUserRequest { string email = 1; string name = 2; string password = 3; }
message UpdateUserRequest { string id = 1; string name = 2; google.protobuf.FieldMask update_mask = 4; }
message DeleteUserRequest { string id = 1; }
message ListUsersRequest { int32 page_size = 1; string page_token = 2; string filter = 3; }
message ListUsersResponse { repeated User users = 1; string next_page_token = 2; int32 total_count = 3; }
message WatchUserRequest { string id = 1; }
message UserEvent {
enum EventType { EVENT_TYPE_UNSPECIFIED = 0; EVENT_TYPE_UPDATED = 1; EVENT_TYPE_DELETED = 2; }
EventType type = 1; User user = 2; google.protobuf.Timestamp timestamp = 3;
}
message BatchCreateUsersResponse { int32 created_count = 1; repeated string failed_emails = 2; }
message ChatMessage { string sender_id = 1; string text = 2; google.protobuf.Timestamp timestamp = 3; }
```
Protobuf rules: field numbers are forever (never reuse), use `UNSPECIFIED = 0` for enums, `repeated` for lists, `FieldMask` for partial updates, `Timestamp` for dates, version via package name (`userservice.v1`).
### Step 3: Generate Code
```bash
# Python
python -m grpc_tools.protoc -I proto --python_out=gen --grpc_python_out=gen --pyi_out=gen proto/user_service.proto
# Go
protoc -I proto --go_out=gen --go_opt=paths=source_relative --go-grpc_out=gen --go-grpc_opt=paths=source_relative proto/user_service.proto
```
Node.js can load protos dynamically (no codegen needed):
```javascript
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const packageDef = protoLoader.loadSync('proto/user_service.proto', {
keepCase: true, longs: String, enums: String, defaults: true, oneofs: true,
});
const proto = grpc.loadPackageDefinition(packageDef).userservice.v1;
```
### Step 4: Server Implementation (Node.js)
```javascript
const userService = {
GetUser(call, callback) {
const user = users.get(call.request.id);
if (!user) return callback({ code: grpc.status.NOT_FOUND, message: `User ${call.request.id} not found` });
callback(null, user);
},
CreateUser(call, callback) {
const { email, name } = call.request;
const user = { id: crypto.randomUUID(), email, name, role: 'ROLE_USER', created_at: { seconds: Date.now() / 1000 } };
users.set(user.id, user);
callback(null, user);
},
WatchUser(call) { // Server streaming
const interval = setInterval(() => {
const user = users.get(call.request.id);
if (user) call.write({ type: 'EVENT_TYPE_UPDATED', user, timestamp: { seconds: Date.now() / 1000 } });
}, 5000);
call.on('cancelled', () => clearInterval(interval));
},
BatchCreateUsers(call, callback) { // Client streaming
let created = 0; const failed = [];
call.on('data', (req) => { users.set(crypto.randomUUID(), { email: req.email, name: req.name }); created++; });
call.on('end', () => callback(null, { created_count: created, failed_emails: failed }));
},
Chat(call) { // Bidirectional streaming
call.on('data', (msg) => call.write({ sender_id: 'server', text: `Received: ${msg.text}` }));
call.on('end', () => call.end());
},
};
const server = new grpc.Server();
server.addService(proto.UserService.service, userService);
server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {});
```
### Step 5: Client Implementation
```javascript
const client = new proto.UserService('localhost:50051', grpc.credentials.createInsecure());
// Unary with deadline
const deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 5);
client.GetUser({ id: '123' }, { deadline }, (err, user) => { if (!err) console.log(user); });
// Server streaming
const stream = client.WatchUser({ id: '123' });
stream.on('data', (event) => console.log('Event:', event));
// Client streaming
const batch = client.BatchCreateUsers((err, resp) => console.log(`Created: ${resp.created_count}`));
batch.write({ email: 'alice@test.com', name: 'Alice' });
batch.write({ email: 'bob@test.com', name: 'Bob' });
batch.end();
```
### Step 6: Error Handling
```
gRPC Status Codes:
NOT_FOUND (5) — Resource missing (like HTTP 404)
INVALID_ARGUMENT (3) — Bad input (like HTTP 400)
UNAUTHENTICATED (16) — Not authenticated (like HTTP 401)
PERMISSION_DENIED (7) — Forbidden (like HTTP 403)
ALREADY_EXISTS (6) — Duplicate (like HTTP 409)
RESOURCE_EXHAUSTED (8) — Rate limited (like HTTP 429)
DEADLINE_EXCEEDED (4) — Timeout
UNAVAILABLE (14) — Service down (like HTTP 503)
INTERNAL (13) — Server error (like HTTP 500)
```
### Step 7: Testing with grpcurl
```bash
brew install grpcurl
grpcurl -plaintext localhost:50051 list
grpcurl -plaintext -d '{"email": "alice@test.com", "name": "Alice"}' \
localhost:50051 userservice.v1.UserService/CreateUser
```
## Examples
### Example 1: Build a user microservice with gRPC
**User prompt:** "Create a gRPC user service in Node.js with CRUD operations and server streaming for live user updates."
The agent will:
1. Create `proto/user_service.proto` with `UserService` defining `GetUser`, `CreateUser`, `ListUsers` (unary RPCs) and `WatchUser` (server streaming)
2. Load the proto dynamically using `@grpc/proto-loader`
3. Implement handlers for each RPC method, using proper status codes (`NOT_FOUND`, `ALREADY_EXISTS`)
4. Start the server on port 50051 and verify with `grpcurl -plaintext localhost:50051 list`
### Example 2: Add batch user import with client streaming
**User prompt:** "Add a batch import endpoint to the user service that accepts a stream of user records from a CSV file and returns a summary of created/failed records."
The agent will:
1. Add a `BatchCreateUsers(stream CreateUserRequest) returns (BatchCreateUsersResponse)` RPC to the proto file
2. Implement the server handler with `call.on('data')` to process each streamed request, tracking created count and failed emails
3. Build a client script that reads the CSV, streams each row as a `CreateUserRequest`, and calls `batch.end()` when done
4. Return the `BatchCreateUsersResponse` with `created_count` and `failed_emails` array
## Guidelines
1. **Proto design is your API contract** — review it as carefully as database schemas
2. **Never change field numbers** — add new fields, deprecate old ones with `reserved`
3. **Use `FieldMask` for updates** — distinguishes "not sent" from "set to empty"
4. **Always set deadlines** — unbound calls leak resources; 5-30s for most RPCs
5. **Enable reflection in dev** — makes debugging with grpcurl/grpcui easy
6. **Health checks on every service** — standard gRPC health protocol for load balancers
7. **Interceptors for cross-cutting concerns** — auth, logging, metrics, tracing
8. **Use streaming sparingly** — unary RPCs are simpler to debug and load-balance
9. **Version via package name** — `userservice.v1`, `userservice.v2`
10. **Keep messages small** — gRPC default max is 4MB; large payloads should be chunked