Skip to main content

Introduction and overview

You can run your own code as an action within Inngest. This gives you the flexibility to do whatever you need within a workflow.

To run your own code it must be containerized. Once in a container, you can use the Inngest CLI to deploy your action. Run inngestctl actions new to generate your action configuration, and run inngestctl actions deploy ./action.cue to deploy.

Your code can read workflow metadata from its input arguments. The first output written to stdout will be captured as part of the workflow data. Anything written to stderr is logged.

Examples can be found here:

You can run your own code as an action without configuring servers or infrastructure, in any language you prefer.

Getting started

The basic flow for creating and deploying your own serverless actions is:

  1. Install the Inngest CLI
  2. Set up your account's identifier
  3. Create a Docker image to package your code
  4. Create a new action using the CLI: inngestctl actions new "test-action" > action.cue
  5. Edit the configuration to point to your Docker image
  6. Publish your action using the CLI: inngestctl actions deploy ./action.cue

You can see example serverless functions defined here:

Account identifier

Your account identifier uniquely represents your account, and it must be configured before creating custom actions. You can configure your account identifier within your settings.

You can choose any account identifier, though it must be a lowercase string using only letters and dashes. It's best to use your company name or personal name:

  • Acme, Inc would use acme-inc
  • Legendary Host would use legendary-host
  • John Wick would use john-wick

This identifier is used to prefix your action DSNs in the configuration. For example, if Acme, Inc creates an action with the identifier hello-world, the action's identifier (DSN) is acme-inc/hello-world.


There is a minimal amount of configuration that must be created to deploy a Docker image as an action. An example of the configuration looks as follows:

package main

import (

action: actions.#Action
action: {
dsn: "account-identifier/hello-world"
name: "Hello world"

# Only one major-minor version for an action can exist.
version: {
# Major versions must be incremented for backwards incompatible changes. Workflows
# specify the major version of the action to use, and automatically use the latest
# minor version available.
# Major updates should be relatively rare, and are generally only specified so that
# existing workflows do not automatically upgrade to the new release.
major: 1

# Minor specifies the minor version for this action. When releasing bugfixes or
# backwards compatible updates, this version must be incremented.
minor: 1

# This allows you to specify workflow-specific configuration which can be set within
# the workflow UI or workflow configuration file.
workflowMetadata: {}

# Response defines the fields within your response.
response: {}

# Edges allows you to configure predefined edges for use within the workflow UI.
# For example, if your action responds with a `success` boolean, you can configure
# a "success" and "fail" edge for easy configuration within the workflow UI.
edges: {}

# Runtime specifies how the image will run. You must change the image to point to
# the local image name to be deployed. This can be an image, or an image and tag.
runtime: {
image: "your-docker-image:latest"
type: "docker"

# entrypoint is an optional string which serves as the command to run within the container
# on boot. If not required, this uses the ENTRYPOINT from your Dockerfile.
entrypoint: "/"

# You can optionally specify the amount of memory to use via the memory field.
# The memory amount must be increments of 128MB, with a max of 8GB.
memory: 256


There are several things to note when implementing your own code as a container:

  1. The workflow context data is passed in as the first argument to your command or entrypoint.
  2. Data written to stdout is captured as part of the workflow context. You should write one JSON encoded payload to stdout as the response to your contianer.
  3. Data written to stderr is logged for debugging.

The rest is up to you - you can run your choice of language and framework.

Workflow context

The workflow context sent as the first argument to your Docker command has the following structure, as a JSON encoded string:

"args_version": 1, // The version for this data structure. This will always be present.
"metadata": {}, // The metadata configured for this action within the worflow
"baggage": "", // The current baggage, as a JSON encoded string.
"baggage_url": "" // A URL to the workflow context, if the context is greater than 8KB.

You can parse the arguments as JSON to get the current workflow baggage - including all data from past actions.


Your serverless functions have the following limits:

  • Up to 8GB ram
  • 5GB disk space
  • Up to 6 hours of runtime

Workflows run in soft-realtime when triggered by events, so even though your serverless code can run for up to 6 hours we recommend finishing as quicky as possible.


You pay for only what you use. You're charged for the number of invocations and the time it takes for your code to execute. During our beta period, functions run for free.

Differences to AWS Lambda

  • You can run any code, without using an SDK to initialize your function.
  • 5GB temporary disk space, vs 512MB plus EFS or S3
  • 6 hours of runtime, vs 15 minutes