Airplane quickstart guide
This guide will walk you through using Airplane to set up an example task and runbook to give you a rough sense of the Airplane platform. We'll end up with a runbook that deletes a user and sends out a link to a temporary archive of their data. Along the way, we'll explore a couple of key Airplane features including adding parameters, deploying code, and referencing output.
Our use case
We're going to create a workflow in Airplane that lets non-engineers perform a "delete user" operation. This is a common use case for Airplane. Companies need to delete users due to GDPR or CCPA reasons, and being able to deploy a script to Airplane that performs this operation lets non-engineers perform the task safely.
First, we're going to create a task in Airplane that performs a user deletion. Then, we'll build a runbook that uses that task and also sends out a Slack notification afterwards.
Create a task
We're going to create a GDPR deletion task that deletes a user's data by looking up their email.
Tasks can either be created through the web UI or through the Airplane CLI. In this guide, we'll use the web UI for convenience.
Start from the Library page on Airplane. From here, click
Create a task
to reach the new task page and select Node from the options.

In this tutorial, we're going to select Node. For this user deletion task, we want to write a custom JS script that hits a deletion endpoint that we've already defined.

Define your task
Fill in the task definition form with the following values:
- Name: Delete user by email
- Description: Permanently deletes a user who has a matching email
- Folder: Ignore this for now
Since we're using the user's email to determine which user to delete from the system, whoever runs
this task will need to input the user's email. Let's add a
parameter that represents the user's email. Click
Add parameter
and enter the following information:
- Name: User email
- Description: The email address of the user to be deleted
- Type: Short text

Once you click the Add
button, it will take you back to the task definition screen where you can
now see the parameter you just input listed there along with the task name and description.

Once the fields under the task definition screen have been completed, click Continue
.
Build your task
Since this is a Node script, we can add in environment variables or select the version of Node that we want to use to run this script. For this tutorial, the default Node version will be sufficient, and we don't need any env vars.

Task advanced settings
The next screen displays "Advanced settings". You can set explicit permissions here and assign users
and groups to specific roles, such as admin or requestor. Let's leave these as team access for this
task and click Create task
.

You've created the task but there's no code backing the task yet! Now we'll write and deploy some JavaScript to implement our code.
Using the CLI to deploy your task
After you click Create task
, you'll see a short list of instructions on how to deploy the code.

If you haven't yet, first install the Airplane CLI (airplane
) by following the
installation instructions.
Once you've installed and logged in to the CLI, create an empty folder and navigate inside it.
bashCopied1mkdir airplane_test2cd airplane_test
From within this directory, you can run the init
command shown on the task page:
bashCopied1airplane init --from delete_user_by_email
Enter a name for the script and the definition file. The script contains the task code
(delete_user_by_email.js
) while the definition file contains task metadata
(delete_user_by_email.task.yaml
). Press ENTER
to stick with the default filenames.
To use TypeScript, use a .ts
extension instead of .js
for the script.
Once the initialization is complete, you'll have two new files that represent your new Airplane task.
Definition file
The definition file (delete_user_by_email.task.yaml
) contains the task metadata that we set up in
the web UI. It will look something like this:
yamlCopied1name: Delete user by email2slug: delete_user_by_email3description: Permanently deletes a user who has a matching email4parameters:5- name: User email6slug: user_email7type: shorttext8description: The email address of the user to be deleted9node:10entrypoint: delete_user_by_email.js11nodeVersion: "16"12timeout: 3600
Script
The file delete_user_by_email.js
contains the actual Node.js script. It looks something like this:
javascriptCopied1// Put the main logic of the task in this function.2export default async function (params) {3console.log("parameters:", params);45// You can return data to show output to users.6// Output documentation: https://docs.airplane.dev/tasks/output7return [8{ element: "hydrogen", weight: 1.008 },9{ element: "helium", weight: 4.0026 },10];11}
For Node.js scripts, Airplane looks for the default export function and calls it. The first
argument will contain the parameters for the run.
When we configured our task, we created a single parameter, "user email". This means that params
will be an object:
javascriptCopied1{2user_email: "email@example.com";3}
Deploy
We'll modify this code in a bit, but just to test it out, you can deploy the task:
bashCopied1airplane deploy delete_user_by_email.task.yaml
This will bundle up the source code, build it, and deploy it to Airplane. Deploying can take a couple of minutes. Once the deployment is finished, find the task in the Airplane UI.

Enter any email and hit Execute task
. The task should succeed. At the bottom of the results page
you will see the output that your task returned:

Create a non-trivial task
Now, let's modify our task to do something a bit more interesting. This is a "Delete user by email" task, so we want our script to actually delete the user. In order to do this, we'll make an HTTP request to a sample API endpoint that we've setup for you.
In the directory with our script, let's create an NPM package. If you're using PowerShell on Windows, you'll need to install Node.js.
bashCopied1# This creates a package.json file. Make sure you're not in a directory2# that already has one!3npm init -y
Next, let's install the airplane
SDK as well as node-fetch
:
bashCopied1npm install airplane node-fetch
This should have updated your package.json
with airplane
and node-fetch
. The Airplane CLI
looks for package.json
when deploying and will use it to install dependencies. Both NPM and Yarn
lock files are supported.
Update your delete_user_by_email.js
script with the following code:
javascriptCopied1import airplane from "airplane";2import fetch from "node-fetch";34export default async function (params) {5// Send an API request to lookup this user's ID.6const getResp = await fetch(`https://demos.airplane.sh/users/get?email=${params.user_email}`);7if (getResp.status !== 200) {8airplane.setOutput(`Failed to get user: ${getResp.status}`, "error");9process.exit(1);10}11const { user } = await getResp.json();1213// Send another API request to perform the deletion, using the ID from the previous request.14const delResp = await fetch(`https://demos.airplane.sh/users/delete?id=${user.id}`, {15method: "delete",16});17if (delResp.status !== 200) {18airplane.setOutput(`Failed to delete user: ${delResp.status}`, "error");19process.exit(1);20}21const { archive_link, status } = await delResp.json();2223// Output results as a structured table24airplane.setOutput({25email: params.user_email,26archive: archive_link,27status,28});29}
After updating your code and saving, redeploy your code:
bashCopied1airplane deploy delete_user_by_email.task.yaml
Now, navigate back to the Airplane UI in your web browser, and try executing the task again with any
sample email. Click Run again
to take you back to the option to Execute task
. This time, the run
results page will look a bit different:

You'll notice that now the output section is no longer blank. We see a structured table that contains the data returned from the HTTP request we made to our sample API endpoint. It shows the following information:
email
: the email of the user we chose to deletearchive
: A temporary link to the user's historical data so we can email that to them as part of our deletion processstatus
: a status showing whether the deletion succeeded or failed
If you click on Logs
you can still see the raw stdout logs, and if you click on JSON you can see
this output table as a raw JSON object.
Runbooks: Add more steps to your task
Now that you've created a task to delete a user by email, let's add on the second step of the workflow. After the deletion process is complete, we also want to automatically be notified with a link to their historical data.
We're going to use a runbook to do this. Runbooks are multi-step operations that can be used to look up information, execute operations, send notifications, and perform other functions all together. The second step we're adding is sending a Slack notification containing the link to the temporary historical data archive.
Let's start by creating a new runbook from the library.
Define your runbook
Similar to the way we defined our task earlier, we're going to define and add parameters for our runbook.
Let's call this runbook "Delete user and send historical data on Slack" where the runbook "permanently deletes a user based on their email and sends a Slack notification with a link to their historical data." Use the following information:
- Name: Delete user and send link to historical data
- Description: Permanently deletes a user based on their email and sends notification with historical data link
- Folder: Ignore this for now
Since we're using the user's email to determine which user to delete from the system, the input will be the user's email. Let's add a runbook parameter that represents the user's email.
Click add parameter and enter the following information:
- Name: User email
- Description: The email address of the user to be deleted
- Type: Short text
Once you click Add
it will take you back to the runbook definition screen where you now see the
name, description, and parameter you just input listed there.

Once you've defined your runbook, click Continue
, which takes you to the "Build Your Runbook"
screen.
Build your runbook
Runbooks are comprised of a series of single-operations called blocks. Blocks can be tasks or they can be other functions that take in inputs, perform an operation, and produce an output. All tasks can be used as blocks but you don't necessarily need to save every block you use in your runbook as its own task.

For the first block, let's select our Delete user by email
task that we just created. Select the
task from the list on the left.

This will complete the same function as the task we created before returning an output table with email, status, message, and archive.
What we want to do now is use a Slack block to automatically send a Slack message with a link to the user's historical data. You'll recall that this was part of the output table when we ran this task previously. But before we add this second step to the runbook, let's pass in our email parameter and test to see that the task is working as expected.
Test blocks
Under Parameters
at the top, enter any email. You can pass in the email that you're using by
inputing {{params.user_email}}
instead of typing "madhura@example.com" in manually. This will make
it such that the block Delete user by email
will automatically use what you enter in the parameter
when it runs.

When you click Test
, you'll see a preview of the test block appear. The email that you've entered
under the top-level params should be the email that you see in the display box. Click Test
again
to run the task.

The run should have succeeded with the same output we saw from the previous section.

Add a Slack block
In our output, the column archive
has a link to the user's historical data. Now, we want to
automatically send a Slack message with this link. To do this, let's add a second block to the
runbook: a Slack block. You can do this by clicking the + sign just below the Delete user by email
block.

Select Slack
from the block types.

You'll need to connect your team's Slack account to use this. It'll take just a couple of minutes to configure Slack by following the prompts below.

You can find more details on our Slack integration in our docs.

Once configured, your runbook builder should look like the below:

There are two fields here: Channel name and message.
For channel name, type the name of the Slack channel you would like to send the message to.
Reference parameters and output
We want our Slack message to print out the archive
field from our first block, as well as show the
email of the user that was deleted. Input the following into the Message
box:
Copied1User tied to email {{params.user_email}} has successfully been deleted.2The user's historical data can be found here:3{{delete_user_by_email.output.archive}}
{{params.user_email}}
refers to the "user_email" top-level runbook parameter. "Params" is a global object that contains all the parameters of a runbook.{{delete_user_by_email.output.archive}}
will reference the output of yourDelete user by email
block and print what's underarchive
in the structured table.

Click the Test
button on this block and you'll see a preview of the Slack message appear. The
email that you've entered as your param should be the email that you see in the display box and you
should also see the link displayed where you're pulling the archive
column of the structured table
from your previous task's output. Click Test
to run the task and send a Slack message.

You should see that your Slack block succeeded:

Since testing the block executes it, you should also receive a Slack notification with the message that we configured using inputs and outputs from your runbook. You can see that we've successfully referenced the user's email and automatically printed the link to the user's historical data.

Runbook advanced settings
Next, click Continue
in the runbook builder to take you to the "Advanced Settings" screen. You'll
see a similar screen to when you created your Delete user by email
task. You can set explicit
permissions here and assign users and groups to
specific roles. Let's leave these as team access for now and click Create runbook
.

Execute your runbook
Your completed runbook should look something like the below. You can see all tasks and runbooks
you've created in the Library
section of the Airplane sidebar. When you select the runbook you
just created "Delete user and send link to historical data," you'll see a web form with the
parameters you configured.

Fill out the user email with any email and click Execute runbook
to run it. When the runbook
begins running, you'll see each block highlighted in blue if it's currently in progress, green if
it's finished, and grey if it hasn't started yet.

That's it! Congrats on creating your first runbook.
More features
This was a quick onboarding guide to walk you through the basic process of creating a task and then a runbook for a real business use case. Airplane has a lot of use cases and features that we didn't cover in this guide. Here are a few other resources that are worth diving into to learn more:
- Use Airplane schedules as a substitute for cron
- Set blocks in a runbook to run automatically or manually based on if you'd like to prompt your team for an input before your runbook continues to execute
- Configure group-based permissions and approval flows
- Leverage audit logs for monitoring and debugging
You can see a full list of tutorials and guides in our tutorials library.
Thanks for using Airplane and don't hesitate to reach out at hello@airplane.dev or drop us a message
on Intercom (the Help and Support
button in the lower-left corner of the app).