A high-performance file upload/download service built with gRPC streaming in Go. This project demonstrates production-ready patterns for handling large file transfers using bidirectional streaming, PostgreSQL for metadata storage, and filesystem-based file storage.
- Client-Streaming Upload: Efficiently upload large files in chunks without loading entire files into memory
- Server-Streaming Download: Stream files back to clients with configurable chunk sizes
- Metadata Management: Store and retrieve file metadata with PostgreSQL
- User File Listings: Paginated file listings per user
- Soft Delete: Files are soft-deleted for potential recovery
- Input Validation: Comprehensive validation using protovalidate
- Protocol Buffers: Type-safe API definitions with buf.build tooling
- Go 1.25+: Modern Go with generics support
- gRPC: High-performance RPC framework
- Protocol Buffers v3: API schema and code generation
- PostgreSQL: Metadata storage with ACID guarantees
- Buf: Modern protobuf toolchain for linting and code generation
.
├── fileservice/v1/ # Proto definitions
│ └── file_service.proto
├── gen/fileservice/v1/ # Generated Go code
├── cmd/
│ ├── server/ # gRPC server entrypoint
│ └── client/ # Example client
├── internal/
│ ├── database/ # PostgreSQL integration
│ ├── service/ # Business logic
│ └── storage/ # File storage interface
├── migrations/ # SQL migration files
├── buf.yaml # Buf workspace config
└── buf.gen.yaml # Code generation config
- Go 1.25 or higher
- PostgreSQL 12+
- Buf CLI (for proto generation)
# Install buf
brew install bufbuild/buf/buf
# Or
go install github.com/bufbuild/buf/cmd/buf@latest- Clone the repository:
git clone https://github.com/PaulBabatuyi/UploadStream-gRPC.git
cd UploadStream-gRPC- Install dependencies:
go mod download- Set up PostgreSQL database:
createdb uploadstream- Run migrations:
psql -d uploadstream -f migrations/000001_create_files_table.up.sql- Configure environment:
export UPLOADSTREAM="postgresql://user:password@localhost:5432/uploadstream?sslmode=disable"go run cmd/server/main.goThe server will start on localhost:50051.
go run cmd/client/main.goUpload a file by streaming chunks to the server.
Request Flow:
- First message:
FileMetadata(filename, content_type, size, user_id) - Subsequent messages:
bytes chunk(file data)
Response:
message UploadFileResponse {
string file_id = 1;
string filename = 2;
int64 size = 3;
string content_type = 4;
google.protobuf.Timestamp uploaded_at = 5;
}Download a file by receiving chunks from the server.
Request:
message DownloadFileRequest {
string file_id = 1;
}Response Flow:
- First message:
FileInfo(metadata) - Subsequent messages:
bytes chunk(file data)
Retrieve metadata for a specific file.
Request:
message GetFileMetadataRequest {
string file_id = 1;
}List files for a user with pagination.
Request:
message ListFilesRequest {
string user_id = 1;
int32 page_size = 2; // 1-100, default 20
string page_token = 3;
}Soft-delete a file (ownership check enforced).
Request:
message DeleteFileRequest {
string file_id = 1;
string user_id = 2;
}After modifying .proto files:
buf generateThis will regenerate:
gen/fileservice/v1/file_service.pb.go(message types)gen/fileservice/v1/file_service_grpc.pb.go(service stubs)gen/fileservice/v1/file_service.pb.validate.go(validators)
buf lintbuf breaking --against '.git#branch=main'UPLOADSTREAM: PostgreSQL connection string (required)
Files are stored in ./data/files by default. Modify in cmd/server/main.go:
storageLayer := storage.NewFilesystemStorage("./data/files")The service enforces the following validations:
- Filename: 1-255 chars, alphanumeric with spaces, dots, hyphens, underscores
- Content Type: Must match pattern
type/subtype - File Size: 1 byte to 512 MB (configurable)
- User ID: Must be valid UUID
- Page Size: 1-100 files per page
Client streaming allows the client to send large files in chunks without loading the entire file into memory on either side. The server can process chunks as they arrive, making it memory-efficient and suitable for large file transfers.
Server streaming prevents the server from loading entire files into memory. Files are read in chunks and streamed directly to the client, enabling efficient bandwidth utilization and support for partial downloads.
Soft deletes (setting deleted_at timestamp) allow for file recovery and audit trails while keeping the data queryable. Physical deletion can be handled by a separate garbage collection process.
# Run all tests
go test ./...
# Run tests with coverage
go test -cover ./...
# Run tests with race detection
go test -race ./...- Chunk Size: Default 64KB for downloads, configurable up to 4MB per gRPC message limits
- Connection Pooling: PostgreSQL connection pool managed by
database/sql - Streaming: Both upload and download use streaming to avoid memory spikes
- Indexing: Database indexes on
user_idanduploaded_atfor fast queries
- S3-compatible storage backend
- Resume interrupted uploads
- File compression
- Image thumbnail generation
- Virus scanning integration
- Rate limiting per user
- Metrics and observability
- gRPC middleware (auth, logging, tracing)
- Base64 cursor-based pagination
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- gRPC for the excellent RPC framework
- Buf for modern protobuf tooling
- Protocol Buffers for efficient serialization
Paul Babatuyi - @PaulBabatuyi
Project Link: https://github.com/PaulBabatuyi/UploadStream-gRPC