Back to Articles

Protoflow: The Workflow Builder That Turns Your Functions Into Microservices

[ View on GitHub ]

Protoflow: The Workflow Builder That Turns Your Functions Into Microservices

Hook

What if every function call in production automatically generated its own regression test? Protoflow treats production traffic as your test suite, storing I/O pairs that detect breaking changes before they ship.

Context

The microservices dream promised modularity and independent deployment, but delivered complexity taxes that made simple changes expensive. Splitting a monolith means wrestling with service boundaries, API contracts, deployment pipelines, and the eternal question: how small is too small? Junior developers struggle with architectural decisions—should this be a separate service? What belongs in shared libraries? Meanwhile, visual workflow tools like Zapier and n8n democratized automation for non-developers but left software engineers frustrated with their lack of code-level control and testability.

Protoflow occupies the gap between these worlds. It's a visual workflow builder for developers who want to write actual code, not configure boxes. The core philosophy: wrap regular functions into isolated, versioned blocks that communicate via gRPC, then compose them visually. The framework handles service boundaries, networking, and versioning while you write normal Go functions. Think of it as enforced functional decomposition—the tooling makes it easier to write small, isolated blocks than to create monolithic services with global state.

Technical Insight

Protoflow's architecture splits into two components: a Go backend server on port 8000 that manages block execution and a Studio frontend on port 8001 for visual workflow composition. The fundamental unit is a 'block'—a wrapped function with defined inputs and outputs that becomes a standalone gRPC microservice.

Here's what a basic block looks like in practice:

// A simple data transformation block
func ProcessUserData(ctx context.Context, input *UserInput) (*UserOutput, error) {
    // Your business logic here - just a regular function
    normalized := strings.ToLower(input.Email)
    validated := validateEmail(normalized)
    
    return &UserOutput{
        Email: normalized,
        Valid: validated,
        ProcessedAt: time.Now().Unix(),
    }, nil
}

Protoflow wraps this function automatically. The input and output structs define your API contract—change the signature, and the framework detects it as a new version. The function remains testable in isolation; you can unit test it without any framework awareness. But when deployed through Protoflow, it becomes a durable gRPC service that can be composed with other blocks in the visual Studio.

The production I/O testing concept is where things get interesting. Every time a block executes in production, Protoflow can optionally store the input-output pair. These pairs become automatic regression tests. Deploy a new version of your block, replay the production inputs, and the system flags any output mismatches. This is semantic versioning at runtime—the framework knows when your 'patch' actually breaks contracts because the outputs changed unexpectedly.

The architecture encourages what the maintainers call 'zero-to-prod functional decomposition.' Instead of starting with a monolith and painfully extracting services later, you write small blocks from day one. The visual Studio makes dependencies explicit—you can see which blocks call which, trace data flow, and understand the system topology without grep-ing through codebases. Each block has a defined blast radius; bugs are contained to specific nodes in the workflow graph.

From an infrastructure perspective, the framework proxies backend to frontend, suggesting a unified deployment model. You're not separately deploying dozens of microservices with individual CI/CD pipelines. The workflow definition in the Studio compiles to a deployable unit where the framework handles service mesh concerns—discovery, retry logic, and circuit breaking are implicit rather than explicit in your code.

The framework's functional purity bias is deliberate. Global state and shared databases make blocks harder to version and test in isolation. By pushing developers toward pure functions with explicit inputs and outputs, Protoflow reduces the cognitive overhead of 'what does this service depend on?' The answer is always: whatever you passed as input. This constraint feels limiting at first but proves valuable as systems scale—new team members can understand a block by reading its function signature, not tracing database connections and environment variables.

Gotcha

Protoflow is pre-alpha software, and it shows. The documentation exists as 'haphazard notes' rather than formal specifications. Core concepts like state management across blocks, transaction boundaries, and consistency guarantees remain unclear. If your workflow needs to update multiple databases atomically or maintain strong consistency across blocks, you're in uncharted territory. The GitHub repository has 14 stars and minimal community activity—you won't find Stack Overflow answers or community plugins when you hit issues.

The functional decomposition model also has practical limits. Real-world services often need shared state, caching layers, and database connections that don't fit cleanly into the pure function model. How do you handle a block that needs to maintain a connection pool or cache? What about workflows that require transactions spanning multiple blocks? The framework's push toward stateless functions is architecturally clean but operationally challenging for many common patterns. You'll likely find yourself fighting the framework when building anything beyond simple data transformation pipelines. Additionally, the visual workflow model can become unwieldy at scale—composing hundreds of blocks in a UI rarely beats grep-ing through well-structured code.

Verdict

Use if: you're building internal microservices for a small team and want tooling that enforces functional decomposition discipline, or you're prototyping workflow-based architectures and value the ability to visualize data flow while maintaining code-level control. The production I/O testing concept alone is worth experimenting with for internal tools where automatic regression detection from real traffic could catch bugs. Skip if: you need production-grade reliability, comprehensive documentation, or community support—this is too early-stage for anything business-critical. Also skip if your domain requires complex state management, distributed transactions, or patterns that don't fit the pure function model. For production workflow orchestration, use Temporal.io instead; for simpler automation, n8n offers more polish at the cost of less developer control.