Run your Cobra CLI applications in AWS Lambda and invoke them remotely as if they were running locally on your machine.
cobra-lambda bridges the gap between traditional command-line applications and serverless functions. It provides:
- A Go library (wrapper package) - Wrap any Cobra CLI application to run in AWS Lambda with full stdout/stderr capture
- A CLI client - Invoke remote Lambda-hosted CLI applications from your terminal with familiar CLI arguments
- Seamless output handling - Captures and returns all output (stdout, stderr, and Cobra output) as structured data
Perfect for running CLI tools, automation scripts, or administrative commands serverless without maintaining long-running servers.
Install the cobra-lambda CLI tool to invoke remote Cobra applications hosted in Lambda:
go install github.com/JayJamieson/cobra-lambda/cmd/clctl@latestOr build from source:
git clone https://github.com/JayJamieson/cobra-lambda.git
cd cobra-lambda
go build -o clctl cmd/clctl/main.goAdd the wrapper package to your Lambda function project:
go get github.com/JayJamieson/cobra-lambda/wrapperCreate a Lambda handler that wraps your Cobra CLI:
package main
import (
"context"
"encoding/json"
"github.com/aws/aws-lambda-go/lambda"
"github.com/JayJamieson/cobra-lambda/wrapper"
"github.com/spf13/cobra"
)
func Handle(ctx context.Context, event json.RawMessage) (any, error) {
// Parse arguments from Lambda event
var args []string
if err := json.Unmarshal(event, &args); err != nil {
return nil, err
}
// Create your Cobra command
var name string
cmd := &cobra.Command{
Use: "myapp",
Run: func(cmd *cobra.Command, args []string) {
cmd.Printf("Hello, %s!\n", name)
},
}
cmd.Flags().StringVar(&name, "name", "World", "Name to greet")
// Wrap and execute
w := wrapper.NewCobraLambda(cmd)
output, err := w.Execute(args)
if err != nil {
return nil, err
}
// Return structured output
return map[string]any{
"stdout": output.Output,
}, nil
}
func main() {
lambda.Start(Handle)
}Build and deploy to Lambda:
GOOS=linux GOARCH=amd64 go build -o bootstrap main.go
zip function.zip bootstrap
# Deploy to AWS Lambda with runtime: provided.al2Use the CLI client to invoke your Lambda-hosted Cobra app:
# Basic invocation
clctl --name my-lambda-function
# With arguments and flags
clctl --name my-lambda-function --name Alice
# Pass any Cobra CLI arguments
clctl --name my-lambda-function subcommand --flag value arg1 arg2The CLI forwards all arguments after --name [function-name] to your Lambda function.
package main
import (
"github.com/JayJamieson/cobra-lambda/wrapper"
"github.com/spf13/cobra"
)
func example() {
cmd := &cobra.Command{
Use: "greet",
Run: func(cmd *cobra.Command, args []string) {
cmd.Println("Hello from Cobra!")
},
}
w := wrapper.NewCobraLambda(context.TODO(), cmd)
output, err := w.Execute([]string{})
if err != nil {
panic(err)
}
// output.Output contains all captured output
}rootCmd := &cobra.Command{Use: "root"}
subCmd := &cobra.Command{
Use: "deploy",
Run: func(cmd *cobra.Command, args []string) {
cmd.Println("Deploying...")
},
}
rootCmd.AddCommand(subCmd)
w := wrapper.NewCobraLambda(context.TODO(), rootCmd)
output, err := w.Execute([]string{"deploy"})The OutputCapture struct contains all captured output in a single field:
type OutputCapture struct {
// Output contains all captured output from Cobra, stdout, and stderr
Output string
}All output streams (Cobra's SetOut/SetErr, os.Stdout, and os.Stderr) are captured into a single shared buffer, preserving the order of output as it was written.
The wrapper is thread-safe:
- Each
CobraWrapperinstance uses a mutex to serializeExecute()calls - Internal buffers are thread-safe with their own locks
- os.Stdout/os.Stderr are restored after each execution, even on panic
For concurrent executions, create separate wrapper instances per goroutine, or reuse a single instance (executions will be serialized automatically).
The clctl CLI tool invokes remote Lambda functions:
clctl --name <function-name> [cobra-args...]# Simple invocation
clctl --name my-cli-app
# With flags
clctl --name my-cli-app --verbose --output json
# With subcommands
clctl --name my-cli-app deploy --environment prod
# Help
clctl --helpThe CLI uses the AWS SDK for Go v2 and respects standard AWS configuration:
- AWS credentials from
~/.aws/credentialsor environment variables - Region from
AWS_REGIONenvironment variable or AWS config - IAM permissions required:
lambda:InvokeFunction
The cldebug cli allows you to test and debug your Lambda Cobra CLI applications locally without deploying to AWS. It starts your Lambda function as an RPC server and invokes it locally, simulating the Lambda runtime environment.
Install cldebug cli:
go install github.com/JayJamieson/cobra-lambda/cmd/cldebug@latestOr build from source:
git clone https://github.com/JayJamieson/cobra-lambda.git
cd cobra-lambda
go build -o cldebug cmd/cldebug/main.goFirst, build your Lambda function:
go build -o bootstrap ./iac/go-demo/main.goThen invoke it locally with cldebug:
cldebug ./bootstrap arg1 arg2 --flag valueFor rapid development, you can run your Lambda source file directly without building:
cldebug --go-run ./iac/go-demo/main.go arg1 arg2 --flag valueEnable debug logging to see what's happening under the hood:
cldebug --debug ./bootstrap arg1 arg2This will show:
- Lambda process startup
- RPC connection details
- Invocation payload
- Process cleanup steps
Using the example from iac/go-demo/:
# Build the Lambda function
cd iac/go-demo
go build -o bootstrap main.go
# Test locally with cldebug
cldebug ./bootstrap hello world
# Or use go run for faster iteration
cldebug --go-run main.go hello world
# With debug output
cldebug --debug ./bootstrap hello world-
Client Side: The
clctlCLI tool extracts the--nameflag to identify the target Lambda function, then forwards all remaining arguments as a JSON array payload. -
Lambda Side: The wrapper package:
- Intercepts
os.Stdoutandos.Stderrusing pipes - Redirects Cobra's output streams to a shared buffer
- Unmarshals the JSON array of arguments
- Executes the Cobra command with the provided arguments
- Returns all captured output as structured data
- Intercepts
-
Response: The client displays the returned output, making the remote execution feel like a local CLI invocation.
See the iac/ directory for complete examples:
iac/go-demo/- Go-based Cobra CLI wrapped for Lambdaiac/node-demo/- Node.js implementation showing the same patterniac/main.tf- Terraform configuration for deploying Lambda functions
MIT