---
title: Inputs / Outputs
description: Learn how to use different inputs and outputs in your workflows.
---

Inputs and outputs are the way to communicate between steps in a workflow. In the previous example,
we used `StartEvent` and `StopEvent` to communicate between steps. However, you can use any type of event to communicate between steps.

## Multiple inputs

You can define multiple inputs for a step.

In the following example, we define a complex workflow with multiple inputs and outputs.

```ts twoslash
import { Workflow, StartEvent, StopEvent, WorkflowEvent } from '@llamaindex/workflow';

class AEvent extends WorkflowEvent<string> {
	constructor(data: string) {
		super(data);
	}
}

class BEvent extends WorkflowEvent<number> {
	constructor(data: number) {
		super(data);
	}
}

class ResultEvent extends WorkflowEvent<string> {
	constructor(data: string) {
		super(data);
	}
}
```

First, let's define the events that we will use in the workflow.

```ts twoslash
import { Workflow, StartEvent, StopEvent, WorkflowEvent } from '@llamaindex/workflow';

class AEvent extends WorkflowEvent<string> {
	constructor(data: string) {
		super(data);
	}
}

class BEvent extends WorkflowEvent<number> {
	constructor(data: number) {
		super(data);
	}
}

class ResultEvent extends WorkflowEvent<string> {
	constructor(data: string) {
		super(data);
	}
}

const workflow = new Workflow<never, string, string>();

workflow.addStep({
	inputs: [StartEvent<string>],
	outputs: [StopEvent<string>]
}, async (
	context,
	startEvent
) => {
	const input = startEvent.data;
	const aEvent = await context.requireEvent(AEvent);
	const bEvent = await context.requireEvent(BEvent);
	const a = aEvent.data;
	const b = bEvent.data;
	return new StopEvent(`Hello, ${input}! A: ${a}, B: ${b}`);
});

// ---cut---
workflow.addStep({
	inputs: [AEvent, BEvent],
	outputs: [ResultEvent]
}, async (
	context,
	aEvent,
	bEvent
) => {
	const a = aEvent.data;
	const b = bEvent.data;
	return new ResultEvent(`A: ${a}, B: ${b}`);
});
```

This step means that it requires two events: `AEvent` and `BEvent`. It will return a `ResultEvent` with the data `A: ${a}, B: ${b}`.

## A or B input

If we want to have a step that can accept either `AEvent` or `BEvent`, we can define the step like this:

```ts twoslash
import { Workflow, StartEvent, StopEvent, WorkflowEvent } from '@llamaindex/workflow';

class AEvent extends WorkflowEvent<string> {
	constructor(data: string) {
		super(data);
	}
}

class BEvent extends WorkflowEvent<number> {
	constructor(data: number) {
		super(data);
	}
}

class ResultEvent extends WorkflowEvent<string> {
	constructor(data: string) {
		super(data);
	}
}

const workflow = new Workflow<never, string, string>();

workflow.addStep({
	inputs: [StartEvent<string>],
	outputs: [StopEvent<string>]
}, async (
	context,
	startEvent
) => {
	const input = startEvent.data;
	const aEvent = await context.requireEvent(AEvent);
	const bEvent = await context.requireEvent(BEvent);
	const a = aEvent.data;
	const b = bEvent.data;
	return new StopEvent(`Hello, ${input}! A: ${a}, B: ${b}`);
});

// ---cut---
workflow.addStep({
	inputs: [WorkflowEvent.or(AEvent, BEvent)],
	outputs: [ResultEvent]
}, async (
	context,
	aOrBEvent
) => {
	if (aOrBEvent instanceof AEvent) {
		// ^?


		const a = aOrBEvent.data;
		//        ^?


		return new ResultEvent(`A: ${a}`);
	} else {
		const b = aOrBEvent.data;
		//        ^?


		return new ResultEvent(`B: ${b}`);
	}
});
```

This step means that it requires either `AEvent` or `BEvent`. It will return a `ResultEvent` with the data `A: ${a}` or `B: ${b}`.

You can still combine the logic with `context.requireEvent` to get the data from the event.

import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';

<Accordions>
	<Accordion title="Under the hood">
		We use JavaScript Inheritance and the prototype chain to implement the `or` logic.
		The `or` method creates a new class that extends the two classes that you pass to it.

		<a
			target="_blank"
			href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain"
		>
			MDN - Inheritance and the prototype chain
		</a>
	</Accordion>
</Accordions>

## Multiple outputs

You can define multiple outputs for a step.

```ts twoslash
import { Workflow, StartEvent, StopEvent, WorkflowEvent } from '@llamaindex/workflow';

class AEvent extends WorkflowEvent<string> {
	constructor(data: string) {
		super(data);
	}
}

class BEvent extends WorkflowEvent<number> {
	constructor(data: number) {
		super(data);
	}
}

class ResultEvent extends WorkflowEvent<string> {
	constructor(data: string) {
		super(data);
	}
}

const workflow = new Workflow<never, string, string>();
// ---cut---
workflow.addStep({
	inputs: [StartEvent<string>],
	outputs: [AEvent, BEvent]
}, async (
	context,
	startEvent
) => {
	const input = startEvent.data;
	if (Math.random() > 0.5) {
		return new AEvent(`Hello, ${input}!`);
	} else {
		return new BEvent(42);
	}
});
```

This step will return either an `AEvent` or a `BEvent` based on a random number.
