Local development
Windmill has its own integrated development environment, but you can also develop and run scripts locally, both with self-hosted and cloud instances.
To simply create and edit scripts and flows locally, you can directly go to the Develop Locally section.
For a more complex setup involving Git, you can go to the Local development Recommended Setup.
Local development recommended setup
Local development involves two components:
- Being able to create and edit Windmill scripts and flow from your favorite IDE.
- Deploy them to Windmill and at the same time version them in a Git repository.
In addition to the core functionalities just mentioned, some might want to add the concept of deployment. This encompasses having a staging and production Windmill environment, and being able to deploy from Staging to Production.
The diagram below illustrates the full process. We're going to explain it quickly, and in the following sections we will decompose it.
It works as follows:
- 2 different workspaces exist in Windmill: one for Staging and one for Prod, and a Git repository that has been set to sync the Windmill Staging workspace.
- Some developers work from their favorite IDE. They can create new Windmill scripts and flows, edit existing ones, and push them to the Staging repository. Some developers can work directly in Windmill's web IDE. All of this happens in the Staging workspace.
- Every time a script or a flow is deployed in the Staging workspace, Windmill will automatically commit the change to the Git repository using Git sync. It can either commit directly to a specific (i.e.
staging
) branch, or open PRs to this branch (one PR per script/flow). - Within the Git repository, every time the
staging
branch is merged into the production branch (i.e.main
), all the changes are pushed at once the Windmill Production workspace.
To summarize, developers operate only in Windmill Staging workspace. Windmill Production workspace is updated only by the CI when the Git staging branch is merged into the production branch.
Now let's deep dive into the first part. We will first explain how developers can set up their local environment to be able to create and edit Windmill script from their IDE, then we will see how to sync Windmill workspaces to a Git repository.
The second part is well covered in:
Develop locally
You can develop locally by using Windmill CLI to clone a workspace and edit scripts and flows in your favorite IDE.
Here is a quickstart video:
All details and commands are available below.
Setting up the workspace folder
Developing Windmill scripts and flows from your favorite IDE is made easy by using Windmill CLI. Here we will go through the full process of cloning a Windmill workspace locally, creating and editing new scripts and flows, and pushing them back the Windmill workspace.
The first step is to clone an existing Windmill workspace into a local folder.
Create an empty folder:
mkdir myworkspace
cd myworkspace
Add the workspace and pull its the content using the CLI pull
command:
wmill workspace add myworkspace [workspace_id] [remote]
wmill sync pull
This will download the content of the workspace into your local folder. You will see an f/
and a u/
folder appearing, replicating the folder structure of the workspace.
wmill sync pull
will pull everything from the Windmill workspace, including resources and variables, even secrets. If you're planning to use Git as explained below, we recommend only pulling scripts, flows and apps, skipping the rest. It can be done with:
wmill sync pull --skip-variables --skip-secrets --skip-resources
Each script will be represented by a content file (.py
, .ts
, .go
depending on the language) plus a metadata file (ending with .script.yaml
). This file contains various metadata about the script, like a summary and description, but also the content of the lockfile and the schema of the script (i.e. the signature of its main
method). We will come back to this later.
For flows, one flow will be represented by a folder, containing a flow.yaml
file being the definition of the flow, and additional files for inline scripts.
The metadata file schema is available here.
Editing and creating scripts locally
To summarize, here are the canonical process to edit and create scripts locally using Windmill CLI (details below):
# optional - create a new script using the CLI (can be done manually)
wmill script bootstrap f/my_space/example_script python3
# edit the script content manually, writing your python code within your IDE
# edit the script metadata (required if you made edits to the dependencies or the main signature method)
wmill script generate-metadata
# optional - specify the path to the script adding f/my_space/example_script.py
wmill script generate-metadata f/my_space/example_script.py
# push your changes to the Windmill workspace
wmill sync push
... and for flows:
# optional - create a new script using the CLI (can be done manually)
wmill flow bootstrap f/my_space/groundbreaking_flow
# edit the flow definition manually, or using the VSCode extension
# push your changes to the Windmill workspace
wmill sync push
Once the workspace folder is pulled, edits can be made using any IDE (including the VS Code extension).
When created and edited through the UI (Windmill App), the lockfile is automatically generated. On local development, each script gets:
- a content file (
script_path.py
,script_path.ts
,script_path.go
, etc.) that contains the code of the script, - a metadata file (
script_path.yaml
) that contains the metadata of the script, - a lockfile (
script_path.lock
) that contains the dependencies of the script.
You can get those 3 files for each script by pulling your workspace with command wmill sync pull
.
Editing a script is as simple as editing its content. The code can be edited freely in your IDE, and there are possibilities to even run it locally if you have the correct development environment setup for the script language.
Metadata file and lockfile
Some fields of the metadata file can also be edited by hand, like the summary of the description fields. If you update the dependencies of your script, or the signature of the main
method, the lockfile and/or the script schema will need to be updated. We do not recommend doing it by hand.
Windmill CLI comes with a wmill script generate-metadata
command that will read all the files that have been edited and gracefully update the metadata file and lockfile accordingly.
This command is mainly used update the lockfile and schema inplace. Be re-assured, any manual update to other files like summary and description will be kept:
Generate metadata command:
And the modified files:
Note that you can explicitly exclude (or include) specific files or folders to be taken into account by this command, with a wmill.yaml
file.
You can also generate metadata for a single script with wmill script generate-metadata <path>
.
The lockfile is not meant to be edited manually. It is generated by Windmill when the script is created or edited through the UI and updated locally with the wmill script generate-metadata
command. However, it is useful to check versions changes.
For each language, there is a way to pin the version directly within script. This is the recommended way of managing dependencies.
Locally, the lockfile is respected. It "wins" over the dependencies pinned via the script. Hence the need of the generate-metadata
command to update the lockfile and metadata files.
Locally, flows and apps are stored in a folder ending with .flow
and .app
respectively. They include a flow.yaml
and app.yaml
file respectively, and the 3 files mentioned above for each inline script they contain.
Package.json & requirements.txt
If you have a package.json
or requirements.txt
file in the same or parent directory as your script, the wmill script generate-metadata
command will automatically include the dependencies in the metadata file.
The lockfile for a file generated with generated-metadata will be overriden by the closest package.json from a parent or current folder if there is one.
But what if you want to create a new script from scratch? It's also easy, just create a file with the correct extension (or run wmill script bootstrap <path> <language>
), and simply run generate-metadata
command to generate the metadata file. The name of the file and its location in the folder will become the script path in Windmill.
File extension per script language
Script language | Expected file extension |
---|---|
TypeScript (deno) | .ts |
Python | .py |
TypeScript (bun) | .bun.ts |
Bash | .sh |
Go | .go |
REST | .fetch.ts |
PostgreSQL | .pg.sql |
MySQL | .my.sql |
BigQuery | .bq.sql |
Snowflake | .sf.sql |
MS SQL Server | .ms.sql |
GraphQL | .gql |
PowerShell | .ps1 |
Similar for flow, you can manually create a folder ending with .flow
and containing a flow.yaml
file.
flow.yaml
initial content
summary: ''
description: ''
value:
modules: []
schema:
$schema: 'https://json-schema.org/draft/2020-12/schema'
type: object
order: []
properties: {}
required: []
ws_error_handler_muted: false
More info here.
Flows can be more difficult to edit at the beginning because ones need to be familiar with the OpenFlow definitions to be able to write the YAML file. To help you with that, you can use our VS Code extension.
Windmill CLI also has a bootstrap
command (both for wmill script
and wmill flow
) which can be used to create a new script in the desired language or flow. All files will be automatically created and the script content will be a simply "Hello world" in the desired language, which can then be updated.
Lastly, it is possible to execute scripts locally and even plug them to any unit testing framework. More info on the Run locally documentation page.
VS Code extension
The Windmill VS Code extension allows you to build scripts and flows in the comfort of your VS Code editor, while leveraging Windmill UIs for test & flows edition.
Deploy from GitHub/GitLab with Staging/Prod
Syncing directly from the CLI is great, but instead of using the CLI directly, you should combine it with your CI/CD and set up a full productive Git workflow with a Staging and Prod workspaces and Git sync. See more details here:
Run locally
Windmill has its own integrated development environment. But for iteration, integration with CI/CD and testing purposes you may need to run a script locally that also interacts with Windmill (for example, to retrieve resources). It will allow you to integrate Windmill with any testing framework.
To setup a local development environment for Windmill, see the dedicated Local development page (above).
To run scripts locally, you will need to fill out the context variables that would otherwise be filled out by the Windmill runtime for you.