Skip to content
step is a framework for building, testing and deploying AWS Step Functions and Lambda
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci exp Jan 25, 2019
assets Updating README and improving method signatures Nov 30, 2018
aws [Fix] Multi-region AWS configurations Apr 8, 2019
bifrost [Feature] adding the default log file so that deployers work Feb 8, 2019
client Updating client to support resource interpolation Dec 5, 2018
deployer Updating client to support resource interpolation Dec 5, 2018
errors [Refactor] moving errors here, refactroing execution, moving clinet f… Jul 16, 2018
execution [Fix] Expose exeution details Jan 25, 2019
handler Updating README and improving method signatures Nov 30, 2018
jsonpath [Feature] generate dot file output for a statemachine Aug 22, 2018
machine [Refactor] Simplify the parser logic using a collection Jan 21, 2019
utils Updating client to support resource interpolation Dec 5, 2018
.gitignore 🚀 Apr 11, 2018
Dockerfile [Update] moving to go mod Jan 25, 2019
Gemfile.lock [Fix] upgrade geo Aug 16, 2018
go.mod [Update] moving to go mod Jan 25, 2019
step.go Updating README and improving method signatures Nov 30, 2018

Step (Beta)

One Small Step for Go

Step is a opinionated implementation of the AWS State Machine language in Go used to build and test AWS Step Functions and Lambdas. Step combines the Structure of a state machine with the Code of a lambda so that the two can be developed, tested and maintained together.

The three core components of Step are:

  1. Library: tools for building and deploying Step Functions in Go.
  2. Implementation: of the AWS State Machine specification to test with the code together (README).
  3. Deployer: to deploy Lambda's and Step Functions securely (README)

Getting Started

A Step function has two parts:

  1. A State Machine description in JSON, which outlines the flow of execution.
  2. The Lambda Function which executes the TaskFn states of the step function.

Create a State Machine like this:

func StateMachine(lambdaArn string) (machine.StateMachine, error) {
  state_machine, err := machine.FromJSON([]byte(`{
    "Comment": "Hello World",
    "StartAt": "HelloFn",
    "States": {
      "Hello": {
        "Type": "TaskFn",
        "Comment": "Deploy Step Function",
        "End": true

  if err != nil {
      return nil, err

  // Set the Handlers

  // Set Lambda Arn to call with Task States

  return state_machine, nil

TaskFn is a custom state type that injects Parameters to execute the correct handler.

Each TaskFn must have a handler that implements func(context.Context, <input_type>) (interface{}, error). These are defined like:

func CreateTaskFunctions() *handler.TaskHandlers {
  tm := handler.TaskHandlers{}
  // Assign Hello state the HelloHandler
	tm["Hello"] = HelloHandler
	return &tm

type Hello struct {
  Greeting *string

// HelloHandler takes a Hello struct alters its greeting and returns it
func HelloHandler(_ context.Context, hello *Hello) (*Hello, error) {
  if hello.Greeting == "" {
    hello.Greeting = "Hello World"
  return hello, nil

To build a Step Function we then need an executable that can:

  1. Be executed in a Lambda
  2. Build the State Machine
func main() {
  var arg, command string
  switch len(os.Args) {
  case 1:
    fmt.Println("Starting Lambda")
  case 2:
    command = os.Args[1]
    arg = ""
  case 3:
    command = os.Args[1]
    arg = os.Args[2]
    printUsage() // Print how to use and exit

  switch command {
  case "json":
  case "exec":
    printUsage() // Print how to use and exit

  1. ./step-hello-world will run as a Lambda Function
  2. ./step-hello-world json will print out the state machine


A core benefit when using Step and joining the State Machine and Lambda together is that it makes it possible to test your Step Functions execution.

For example, a basic test that ensures the correct output and execution path through the Hello World step function looks like:

func Test_HelloWorld_StateMachine(t *testing.T) {
  state_machine, err := StateMachine("")
  assert.NoError(t, err)

  exec, err := state_machine.Execute(&Hello{})
  assert.NoError(t, err)
  assert.Equal(t, "Hello World", exec.Output["Greeting"])

  assert.Equal(t, state_machine.Path(), []string{


There are two ways to get a State Machine into the cloud:

  1. Bootstrap: Directly upload the Lambda and Step Function to AWS
  2. Deploy: Using the Step Deployer which is a Step Function included in this library.

The Step executable can perform both of these functions.

Step does not create the Lambda or Step Function in AWS, it only modifies them. So before either bootstrapping or deploying the resources must already be created.

First build and install step with:

go build && go install

Bootstrap (directly upload to the Step Function and Lambda):

# Use AWS credentials or assume-role into AWS
# Build linux zip for lambda
GOOS=linux go build -o lambda
zip lambda

# Tell step to bootstrap this lambda
step bootstrap                        \
  -lambda "coinbase-step-hello-world" \
  -step "coinbase-step-hello-world"   \
  -states "$(./step-hello-world json)"

Deploy (via the step-deployer step function):

GOOS=linux go build -o lambda
zip lambda

# Tell step-deployer to deploy this lambda
step deploy                           \
  -lambda "coinbase-step-hello-world" \
  -step "coinbase-step-hello-world"   \
  -states "$(./step-hello-world json)"

Development State

Step is still Beta and its API might change quickly.

More Links

  1. AWS Step Functions, State Machines, Bifrost, and Building Deployers
  2. Open Sourcing Coinbase’s Secure Deployment Pipeline

CC Renee French for the logo, borrowed from GopherCon 2017

You can’t perform that action at this time.