# TypeScript quickstart

> How do I write TypeScript scripts in Windmill? Create, test and deploy TypeScript with Bun, Node.js or Deno runtimes.

In this quick start guide, we will write our first script in TypeScript. Windmill uses [Bun](https://bun.sh/), [Nodejs](#nodejs) and [Deno](https://deno.land/) as the available TypeScript runtimes.

This tutorial covers how to create a simple "Hello World" script in TypeScript through Windmill web IDE, with the standard mode of handling dependencies in TypeScript (Lockfile per script inferred from imports). See the dedicated pages to [develop scripts locally](../../../advanced/4_local_development/index.mdx) and other methods of [handling dependencies in TypeScript](../../../advanced/14_dependencies_in_typescript/index.mdx).

Scripts are the basic building blocks in Windmill. They can be [run and scheduled](../../../triggers/index.mdx) as standalone, chained together to create [Flows](../../../flows/1_flow_editor.mdx) or displayed with a personalized User Interface as [Apps](../../7_apps_quickstart/index.mdx).

Scripts consist of 2 parts:

- [Code](#code): for TypeScript scripts, it must have at least a main function.
- [Settings](#settings): settings & metadata about the Script such as its path, summary, description, [JSON Schema](../../../core_concepts/13_json_schema_and_parsing/index.mdx) of its inputs (inferred from its signature).

When stored in a code repository, those 2 parts are stored separately at `<path>.ts` and `<path>.script.yaml`.

[This](https://hub.windmill.dev/scripts/slack/1284/send-message-to-channel-slack) is a simple example of a script built in TypeScript with Windmill:

```ts

type Slack = {
	token: string;
};

	// Use the chat.postMessage method from the Slack WebClient to send a message
	await web.chat.postMessage({
		channel: channel,
		text: message
	});
}
```

In this quick start guide, we'll create a script that greets the operator running it.

From the Home page, click **New** and select **Script**. This will take you to the first step of script creation: [Metadata](../../../script_editor/settings.mdx#metadata).

## Settings

![New script](../../../../static/images/script_languages.png "New script")

As part of the [settings](../../../script_editor/settings.mdx) menu, each script has metadata associated with it, enabling it to be defined and configured in depth.

- **Summary** (optional) is a short, human-readable summary of the Script. It will be displayed as a title across Windmill. If omitted, the UI will use the `path` by default.
- **Path** is the Script's unique identifier that consists of the [script's owner](../../../core_concepts/16_roles_and_permissions/index.mdx), and the script's name. The owner can be either a user, or a group ([folder](../../../core_concepts/8_groups_and_folders/index.mdx#folders)).
- **Description** is where you can give instructions through the [auto-generated UI](../../../core_concepts/6_auto_generated_uis/index.mdx) to users on how to run your Script. It supports markdown.
- **Language** of the script.
- **Script kind**: Action (by default), [Trigger](../../../flows/10_flow_trigger.mdx), [Approval](../../../flows/11_flow_approval.mdx), [Error handler](../../../flows/7_flow_error_handler.md) or [Preprocessor](../../../core_concepts/43_preprocessors/index.mdx). This acts as a tag to filter appropriate scripts from the [flow editor](../../6_flows_quickstart/index.mdx).

This menu also has additional settings on [Runtime](../../../script_editor/settings.mdx#runtime), [Generated UI](#generated-ui) and [Triggers](../../../script_editor/settings.mdx#triggers).

Now click on the code editor on the left side.

## Code

Windmill provides an online editor to work on your Scripts. The left-side is
the editor itself. The right-side [previews the UI](../../../core_concepts/6_auto_generated_uis/index.mdx) that Windmill will
generate from the Script's signature - this will be visible to the users of the
Script. You can preview that UI, provide input values, and [test your script](#instant-preview--testing) there.

![Demo TS](./demo_ts.png 'Demo TS')

There are two options for runtimes in TypeScript:

- Bun (with a [Nodejs](#nodejs) mode if needed)
- [Deno](#deno)

As we picked `TypeScript (Bun)` for this example, Windmill provided some TypeScript boilerplate. Let's take a look:

```typescript
// there are multiple modes to add as header: //nobundling //native //npm //nodejs
// https://www.windmill.dev/docs/getting_started/scripts_quickstart/typescript#modes

// import { toWords } from "number-to-words@1"

}
```

In Windmill, scripts need to have a `main` function that will be the script's
entrypoint. There are a few important things to note about the `main`.

- The main arguments are used for generating
  1.  the [input spec](../../../core_concepts/13_json_schema_and_parsing/index.mdx) of the Script
  2.  the [frontend](../../../core_concepts/6_auto_generated_uis/index.mdx) that you see when running the Script as a standalone app.
- Type annotations are used to generate the UI form, and help pre-validate
  inputs. While not mandatory, they are highly recommended. You can customize
  the UI in later steps (but not change the input type!).

Also take a look at the import statement lines that are commented out.
In TypeScript, [dependencies](../../../advanced/14_dependencies_in_typescript/index.mdx) and their versions are contained in the script and hence there is no need for any additional steps.
The TypeScript runtime is Bun, which is 100% compatible with Node.js without any code modifications.
You can use npm imports directly in Windmill. The last import line imports the Windmill
client, that is needed for example, to access
[variables](../../../core_concepts/2_variables_and_secrets/index.mdx) or
[resources](../../../core_concepts/3_resources_and_types/index.mdx). We won't go
into that here.

Back to our "Hello World". We can clear up unused import statements, change the
main to take in the user's name. Let's also return the `name`, maybe we can use
this later if we use this Script within a [flow](../../../flows/1_flow_editor.mdx) or [app](../../../full_code_apps/index.mdx) and need to pass its result on.

```typescript

	return { name };
}
```

## Modes

### Pre-bundling and nobundling

Windmill [pre-bundles](/changelog/pre-bundle-bun-scripts) your script at deployment time using [Bun bundler](https://bun.sh/docs/bundler). This improve memory usage and speed up the execution time of your script. If you would like to disable this feature, you can add the following comment at the top of your script:

```ts
//nobundling
```

### Native

Windmill provides a runtime that is more lightweight but supports less features and allow to run scripts in a more lightweight manner with direct bindings to v8. To enable, you can add the following comment at the top of your script:

```ts
//native
```

To learn more, see [Rest](../6_rest_grapqhql_quickstart/index.mdx) scripts, that are under the hood Bun TypeScripts with a `//native` header.

### NodeJS

Windmill provides a true NodeJS compatibility mode. This means that you can run your existing NodeJS code without any modifications.

The only thing you need to do is to select `TypeScript (Bun)` as the runtime and as the first line, use:

```ts
//nodejs
```

![Nodejs Compatibility](./nodejs_compatibility.png 'Nodejs Compatibility')

This method is an escape hatch for using another runtime (NodeJS), but it is slower than Deno and Bun since it resorts to Bun under the hood.

This feature is exclusive to [Cloud plans and Self-Hosted Enterprise edition](/pricing).

### Npm

Similarly, you can use `npm install` instead of `bun install` to install dependencies. This is useful as an escape hatch for cases not supported by bun:

```ts
//npm
```

This is also exclusive to [Cloud plans and Self-Hosted Enterprise edition](/pricing).

### Deno

You can also pick `TypeScript (Deno)` as the language instead of `TypeScript (Bun)`. The walkthrough is the same as with Bun ([above](#code)): a `main` function as entrypoint, an [auto-generated UI](../../../core_concepts/6_auto_generated_uis/index.mdx) from its signature, and [dependencies](../../../advanced/14_dependencies_in_typescript/index.mdx) resolved directly from imports. The differences with Bun are:

- The resolution of imports is done by [Deno](https://deno.com/runtime), so npm imports use the `npm:` prefix (e.g. `import * as wmill from "npm:windmill-client@1.525.0"`), and `https://` and `jsr:` imports are also supported.
- The Bun-specific [modes](#modes) (`//nobundling`, `//native`, `//nodejs`, `//npm`) do not apply.

```typescript
// Deno uses "npm:" prefix to import from npm (https://deno.land/manual@v1.36.3/node/npm_specifiers)
// import * as wmill from "npm:windmill-client@1.525.0"

}
```

## Instant preview & testing

Look at the UI preview on the right: it was updated to match the input
signature. Run a test (`Ctrl` + `Enter`) to verify everything works.

You can change how the UI behaves by changing the main signature. For example, if you add a default for the `name` argument, the UI won't consider this field as required anymore.

```typescript
main(name: string = "you")
```

Now let's go to the last step: the "Generated UI" settings.

## Generated UI

From the Settings menu, the "Generated UI" tab lets you customize the script's arguments.

The UI is generated from the Script's main function signature, but you can add additional constraints here. For example, we could use the `Customize property`: add a regex by clicking on `Pattern` to make sure users are providing a name with only alphanumeric characters: `^[A-Za-z0-9]+$`. Let's still allow numbers in case you are some tech billionaire's kid.

![Advanced settings for TypeScript](./customize_ts.png.webp)

## Workflows as code

One way to write distributed programs that execute distinct jobs is to use [flows](../../../flows/1_flow_editor.mdx) that chain scripts together.

Another approach is to write a program that defines the jobs and their dependencies, and then execute that program directly in your script. This is known as [workflows as code](../../../core_concepts/31_workflows_as_code/index.mdx). Wrap your orchestration function with `workflow()` and annotate task functions with `task()`. Each task runs as a separate job with its own logs and timeline entry, while the workflow suspends between tasks (releasing its worker slot).

![Flow as code in TypeScript](./flow_as_code_ts.png 'Flow as code in TypeScript')

All details at:

## Run!

We're done! Now let's look at what users of the script will do. Click on the [Deploy](../../../core_concepts/0_draft_and_deploy/index.mdx) button
to load the script. You'll see the user input form we defined earlier.

Note that Scripts are [versioned](../../../core_concepts/34_versioning/index.mdx#script-versioning) in Windmill, and
each script version is uniquely identified by a hash.

Fill in the input field, then hit "Run". You should see a run view, as well as
your logs. All script runs are also available in the [Runs](../../../core_concepts/5_monitor_past_and_future_runs/index.mdx) menu on
the left.

![Run hello world in TypeScript](./run_ts.png.webp)

You can also choose to [run the script from the CLI](../../../advanced/3_cli/index.mdx) with the pre-made Command-line interface call.

## Caching

Every bundle on Bun is cached on disk by default. Furthermore if you use the [Distributed cache storage](../../../core_concepts/38_object_storage_in_windmill/index.mdx#instance-object-storage-distributed-cache-for-python-rust-go), it will be available to every other worker, allowing fast startup for every worker.

## What's next?

This script is a minimal working example, but there's a few more steps that can be useful in a real-world use case:

- Pass [variables and secrets](../../../core_concepts/2_variables_and_secrets/index.mdx)
  to a script.
- Connect to [resources](../../../core_concepts/3_resources_and_types/index.mdx).
- [Trigger that script](../../../triggers/index.mdx) in many ways.
- Compose scripts in [Flows](../../../flows/1_flow_editor.mdx) or [Apps](../../7_apps_quickstart/index.mdx).
- You can [share your scripts](../../../misc/1_share_on_hub/index.md) with the community on [Windmill Hub](https://hub.windmill.dev). Once
  submitted, they will be verified by moderators before becoming available to
  everyone right within Windmill.

Scripts are immutable and there is an hash for each deployment of a given script. Scripts are never overwritten and referring to a script by path is referring to the latest deployed hash at that path.

For each script, a UI is autogenerated from the JSON schema inferred from the script signature, and can be customized further as standalone or embedded into rich UIs using the [App builder](../../7_apps_quickstart/index.mdx).

In addition to the UI, sync and async [webhooks](../../../core_concepts/4_webhooks/index.mdx) are generated for each deployment.
