WESL Logo

#wesl.toml file format

WESL shader projects have a standardized wesl.toml file, which describes the project setup. It is used by tools such as language servers and linkers.

The format looks as follows. As much of it is optional as possible.

[package]
# Version of WESL used in this project.
edition = "2026_pre"

# Optional, can be auto-inferred from the existence of a package manager file.
# Inclusion of this field is encouraged.
package-manager = "npm"

# Where are the shaders located. This is the path of `package::`.
root = "./shaders"

# Optional
include = [ "shaders/**/*.wesl", "shaders/**/*.wgsl" ]

# Optional.
# Some projects have large folders that we shouldn't react to.
exclude = [ "**/test" ]

# Lists all used dependencies
[dependencies]
# Shorthand for `foolib = { package = "foolib" }`
foolib = {}
 # Can be used for renaming packages. Now bevy in my code is called "cute_bevy".
cute_bevy = { package = "bevy" }
# File path to a folder with a wesl.toml. Simplest kind of dependency.
mylib = { path = "../mylib" }

#Semantics

A wesl.toml file is mandatory for libraries.

For user applications, feel free to start without a wesl.toml. We’ll assume reasonable defaults, which will evolve over time.

As your application grows, we suggest adding a wesl.toml. This lets you pin down the exact behavior of wesl.

#edition field

Specifies which edition is used by wesl. All wesl editions can be used.

#package-manager field

Which package manager is used for resolving wesl libraries.

It is limited to one package manager to reduce implementation complexity. We do not have any wesl implementations that would allow for mixing and matching packages from different package managers. For dual publishing, the expectation is that one would have a primary package manager, and then attempt to mirror the structure for other package managers.

#root field

Specifies the root folder or root file for the package:: syntax. IDEs watch this directory for changes.

When the wesl.toml file does not exist, then tools should choose one of the following behaviors

#include and exclude fields

Specifies an array of patterns where wesl files are located. The patterns are relative to the wesl.toml file.

The default value of include is all wesl and wgsl files in the root directory, recursively. The default value of exclude is an empty array.

The patterns are glob patterns, which support

If the last path segment does not contain a file extension or wildcard, then it is treated as a directory, and files with .wesl or .wgsl extensions inside that directory are included.

#Path semantics

File paths in the root, include and exclude fields are relative to the directory containing the wesl.toml file. Absolute paths (starting with / or C:/) are not allowed.

#dependencies entry

All used dependencies are explicitly listed here.

Its structure is wesl_name = { package = "name_used_in_package_manager" }. It supports package or path specifications:

This lets us additionally deal with names that would be impossible to spell in WESL. e.g. fun_shaders = { package = "@lorem/fun_shaders" }

#dependencies = "auto"

Instead of specifying a list of dependencies, one can specify dependencies = "auto". Then, the available dependencies are automatically inferred from the list of libraries installed with npm1 or Cargo.

This is an optional, ecosystem-specific feature. See the documentation of the respective implementation for details.

#Q&A

#Description and version fields

Description and version fields do not exist. Instead, we use the package.json/Cargo.toml. Semantics are: We are publishing a normal package that also contain wesl code2. This lets us support wesl packages that come with host code!

#Footnotes

  1. npm, pnpm, yarn… package managers with a node_modules/ directory and package.json file. 2

  2. In Rust land, this is necessary to comply with the crates.io policy of being compatible with the cargo build tool.