Output
Produce human-friendly structured output from your tasks
Reading through logs can be noisy and challenging—Airplane allows tasks to produce explicit
output separate from logs.
Airplane output is displayed in rich, user-friendly tables:

Output data model
Output data model
Airplane output from a task is similar to the return value of a function. Airplane output can be any
JSON value such as primitive values (strings, numbers), lists, or even complex objects.
Different Airplane tasks will return different kinds of output. For example, a
SQL task will return its SELECT results as a list of objects (which is rendered as a
table of values). JavaScript tasks can output values however the author desires.
Output rendering in the UI
Output rendering in the UI
Airplane's UI does a best effort rendering of output, depending on the output data structure. The
output is typically formatted into a table or multiple tables. If the output data structure is an
object containing only lists as values, the UI will render each separate list as its own table, with
the table name set to the key of the list. Otherwise, the entire output will be rendered as one
table.
Primitive values (strings, numbers, booleans) are rendered as a single cell in a table.
Lists of primitive values are rendered as a single column table with multiple rows.
Lists of objects are rendered as a table, one row per item, and one column per key. For example,
[{"id": 1, "name": "John"}, {"id": 2, "name": "Sally"}]
will render as two rows with two columns,
"id" and "name".Nested objects are rendered as collapsed values inside the table.

Producing output from tasks
Producing output from tasks
Non-code tasks (SQL, REST) produce outputs automatically e.g. from the result of a SQL
SELECT
query or REST GET
request.For most code tasks (JavaScript, Python), the easiest way to produce output from a task is by
returning a value from the main function.
typescriptCopied1export default async function (params) {2return { id: 123, name: "abc" };3}
pythonCopied1import airplane23@airplane.task()4def my_task(params):5return {"id": 123, "name": "abc"}
For code tasks that are not based on a main function (Shell, Docker), Airplane captures task output
by filtering stdout lines that start with certain keywords.
For example, in a shell task you can produce output by echoing a string that starts with
airplane_output_set
.shellCopied1#!/bin/bash23data='{"id": 123, "name": "abc"}'4echo "airplane_output_set ${data}"
For more information about creating task outputs via stdout, see the Advanced section
below.
SDK output methods
SDK output methods
If more complicated output structures are needed, the Airplane SDK provides functions for modifying
the output incrementally over the course of the task.
Set output
Set output
You can set the entire output object by calling the appropriate SDK function:
typescriptCopied1import airplane from "airplane";23export default async function (params) {4airplane.setOutput("ABC");5airplane.setOutput("DEF");6// The final output value will be "DEF".7}
pythonCopied1import airplane23@airplane.task()4def my_task():5airplane.set_output("ABC")6airplane.set_output("DEF")7# The final output value will be "DEF".
Note that returning a value from a main function is equivalent to calling the corresponding set
output function at the end of task execution.
Append to output
Append to output
If your output is intended to be an array, instead of setting the entire output to be an array, you
can use the following:
typescriptCopied1import airplane from "airplane";23export default async function (params) {4airplane.appendOutput({ name: "Alabama", capital: "Montgomery" });5airplane.appendOutput({ name: "Alaska", capital: "Juneau" });6airplane.appendOutput({ name: "Arizona", capital: "Phoenix" });7}
pythonCopied1import airplane23@airplane.task()4def my_task():5airplane.append_output({"name": "Alabama", "capital": "Montgomery"})6airplane.append_output({"name": "Alaska", "capital": "Juneau"})7airplane.append_output({"name": "Arizona", "capital": "Phoenix"})
The resulting output will be
[{"name": "Alabama", "capital": "Montgomery"}, {"name": "Alaska", "capital": "Juneau"}, {"name": "Arizona", "capital": "Phoenix"}]
which will be displayed in the UI as:
Common use cases
Common use cases
Displaying user messages
Displaying user messages
By default, users see if a run has succeeded or failed. You can output messages as you make progress
(output is shown as soon as it is received), and you can also output more detailed error messages if
something fails.
Exporting data
Exporting data
You can use Airplane output for lightweight reporting. For example, you can query a database for a
set of data, output each row as a JSON object, and allow users a quick way to see data (and download
it as a CSV).
Advanced
Advanced
Log output protocol
Log output protocol
Under the hood, Airplane captures task output by filtering stdout lines that start with either
airplane_output_set
or airplane_output_append
. In other words, returning from a main function,
or calling any of the SDK output functions, generates an airplane_output_set
or
airplane_output_append
line in stdout, which will be parsed by Airplane to obtain the final
task output.Examples of such log lines are provided below:
Copied1airplane_output_set {"id": 1, "name": "abc"}
Copied1airplane_output_append {"id": 1, "name": "abc"}2airplane_output_append {"id": 2, "name": "def"}
For languages that do not have a SDK provided (e.g. Docker image, shell), printing such log lines to
stdout is the recommended method for generating output from a task.
To produce an output that is a string, ensure the string value is wrapped in double quotes.
Copied1// This will work2airplane_output_set "value"34// This will not work5airplane_output_set value
JSON paths
JSON paths
Setting and appending can also apply to a subset of the output instead of overwriting the entire
output or appending to the main array. The airplane output set and airplane output append commands
have an optional path parameter, which allows part of an existing output to be edited.
Copied1airplane_output_set {"k1": "v1", "k2": {"nested": "abc"}, "k3": [1, 2, 3]}2airplane_output_set:k1 "new value"34# Output is now: {"k1": "new value", "k2": {"nested": "abc"}, "k3": [1, 2, 3]}56# Note that these are all valid path syntaxes.7airplane_output_set:k2.nested "def"8airplane_output_set:k2["nested"] "def"9airplane_output_set:["k2"]["nested"] "def"10airplane_output_set:["k2"].nested "def"1112# Output is now: {"k1": "new value", "k2": {"nested": "def"}, "k3": [1, 2, 3]}1314airplane_output_set:k3[2] 41516# Output is now: {"k1": "new value", "k2": {"nested": "def"}, "k3": [1, 2, 4]}1718# Append also accepts paths.19airplane_output_append:k3 82021# Output is now: {"k1": "new value", "k2": {"nested": "def"}, "k3": [1, 2, 4, 8]}2223# If a set or append command encounters a null or undefined value along the24# path to the final output location, it automatically generates an empty object25# in the output, for convenience.26airplane_output_set:k4.new 52728# Output is now: {"k1": "new value", "k2": {"nested": "def"}, "k3": [1, 2, 4, 8], "k4": {"new": 5}}
The set/append output functions in the SDKs will help to automatically construct the JSON path for
you, from an array of path components. Refer to the documentation of each individual SDK for the
correct format.
Handling large output
Handling large output
Due to limitations of Docker/Kubernetes, output lines in stdout that are too long (greater than
approximately 16000 characters) may not be parsed correctly, so we provide a "chunking" mechanism to
split up such lines.
If you are using a SDK, this chunking is automatically handled for you.
Copied1airplane_chunk:key1 airplane_outp2airplane_chunk:key1 ut_set "Hello World!"3airplane_chunk_end:key145airplane_chunk:key2 airplane_outp6airplane_chunk:key2 ut_set "How ar7airplane_chunk:key2 e you?"8airplane_chunk_end:key2910(is equivalent to)1112airplane_output_set "Hello World!"13airplane_output_set "How are you?"
However, note that there is still a maximum possible size set on output lines, even with chunking
applied. If the size of all combined output line chunks is greater than 4MiB, the output will not be
processed, and a warning message will be included in the run logs instead. Note that this does not
affect any other part of the run (i.e. the run still can succeed) - only the output will be
affected.
Files
Files
Files can be directly returned from a task, and will be displayed in the UI as a
downloadable link. If the file is a text, csv, image, video, or audio file, it will also be rendered
inline in the UI.
typescriptCopied1import airplane from "airplane";23export default airplane.task(4{5slug: "return_image",6parameters: {7image_upload: "upload",8},9},10async (params) => {11return params.image_upload;12},13);
pythonCopied1import airplane23@airplane.task()4def return_image(image_upload: airplane.File):5return image_upload
