The Ludwig Compiler

Click here to return to the Advanced Ludwig table of contents.

lwc is the compiler for the Ludwig language. This guide details lwc usage, arguments, options, and examples.


lwc <FILE> [options]


Ludwig file to compile


-h | --help
Show help text.
-s | --semantics <BACKEND>

Select output backend. Note: Only two semantic backends are recommended for users: -s null and -s simple. -s null displays no output if there are no errors, and is the default backend. -s simple displays JSON output of the compiled composition, or errors if they exist. Other backends are designed for Fugue developer use only.


  • null: No output displayed. Default.
  • tree: Output a flat, tree-structured, strongly normalized form. All variables are inlined and replaced with their definitions. *
  • graph: Deprecated. *
  • proto: Output protocol buffer code. Note: Requires -o | --output-file option. *
  • simple: Output a JSON rendering of the proto version. The output contains UUIDs.
  • snapshot: Output an archive file that can be used to run a composition again. Users who want to re-run a composition can simply execute fugue run again. Note: Requires -o | --output-file option. *
  • swagger: Reserved for future functionality.
Compile a Ludwig file strictly as a composition.
-d | --dump <DUMP1:DUMP2>

Dump debug info to stderr. *


  • modules: Module file paths
  • constraints: Inferred type constraints
  • core: Program core
  • lexer: Lexer output
  • operators: Operator table
  • profiling: Timing information
  • restructure: Graph after restructuring
  • types: Inferred types
  • logs: Logs
  • env: Environment variables used in the composition (via String.getEnv)
  • files: Files used in the composition (via String.readFileUtf8 or Bytes.readFile)
  • evalprofiling: Evaluation timing information
-i | --include-dirs DIR1:DIR2
Include additional search directories for modules.
Run the typechecker only. *
-w | --warnings
Show warnings (default).
Don’t show warnings.
Exit on warnings.
Enable colorized output (default).
Disable colorized output.
--timeout SECONDS
Set length of compilation timeout, in seconds. Default: 10 seconds.
-o | --output-file FILE
Set output file. Required for proto and snapshot backends. Optional for text-based backends. snapshot output files must have a .tar.gz extension.
--validation-modules MODULE1:MODULE2
Specify validation module names.
--set "binding: expr"
Override a Ludwig binding. The binding must have the @override annotation.
--environment-write FILE
Create a JSON file with environment variables and file mapping of the current environment. *
--environment-read FILE
Specify JSON file containing environment variables and file mapping. For use with snapshots. *
--error-format {text | json}
Set format for displaying errors and warnings. Use text for text output and json for JSON output.
Enable caching of compiled modules. Experimental.
Disable caching of compiled modules. Experimental.
Run in lenient mode. Experimental.
--truncate-atoms LENGTH
Truncate the length of output atoms.
Add used module and file paths to output. Experimental.
Evaluate values to normal form when profiling timing.

* These options are meant for Fugue developer use only, and are not supported for customer use.


lwc is the compiler for the Ludwig language. It is built to support numerous backend formats and can verify the logical integrity of Ludwig programs at compile time. The Fugue CLI uses lwc to compile compositions prior to creating or updating a process, but lwc can be used on its own to test compilation.

For more information, see The Ludwig Compiler in Writing Ludwig.


Basic compilation of compositions

To quickly compile a composition, use a command like this:

lwc --composition FILE

If no output is returned, the composition has successfully compiled.

Recurring compilation of compositions

If you are working with Ludwig in an editor and on a platform with the watch command (available on OSX via Homebrew), you can get IDE-like fast feedback by running the following command in a separate pane or window on-screen:

watch -n2 -- lwc --composition FILE

A similar behavior can be achieved in bash without watch this way:

while true; do clear; lwc --composition FILE; sleep 2; done

Overriding a binding in a composition

You can use the --set "binding: expr" option to selectively override bindings marked with an @override annotation when the composition is compiled. This allows you to change a value at compile-time without modifying the composition.

For example, if you have the following composition:

name: "Tommy"

You can add the @override annotation to allow overrides of name:

name: @override "Tommy"

And then you can override name‘s value “Tommy” with the new value “Timmy” by executing the following command:

lwc --set 'name: "Timmy"' Composition.lw

Keep these rules in mind:

  • A binding must include the @override annotation in order to be overridden.
  • You may override multiple bindings by using the --set option more than once.
  • The binding’s type cannot be changed.
  • You currently cannot override Fugue types.

You must include @override

Bindings may only be overridden if they have the @override annotation. Note that bindings are top-level declarations, not fields within records:

# Below, "name" is a binding and may be overridden
name: @override "Tommy"

# Below, "name" is a field in a record, not a binding, and may NOT be overridden:
Person someone:
  name: "Tommy"
  age: 30

# However, you can move the value to a top-level binding and reference it in the record like so:
Person someone2:
  name: someonesName
  age: 30

someonesName: @override "Tommy"

See the Ludwig Syntax Reference to learn about bindings, records, and more.

You may override multiple bindings

When using lwc, you can specify multiple --set arguments to override multiple bindings at once. For example:

lwc --set 'name: "Timmy"' --set 'age: 32' Composition.lw

You can’t change the binding type

The binding’s type may not change. You may substitute a string for a string, an integer for an integer, and so on. You may not substitute a float for a string, or a List<Int> for a List<Bool>.

You can’t override Fugue types

Currently, due to restrictions in the import system, lwc cannot override imported types, so you cannot override Fugue types, such as Fugue.AWS, Fugue.Core, etc. (See the Standard Library Reference for a full list of Fugue types.) For example, you cannot override the Region type (Fugue.AWS.Region) by substituting the constructor Us-east-1 for the constructor Us-west-2.

A real-world example with a CIDR block

If you want to change a VPC’s CIDR block at compile-time instead of modifying the composition, you could use an @override annotation to do it.

Let’s say this is the original VPC composition:


import Fugue.AWS as AWS
import Fugue.AWS.EC2 as EC2

exampleVpc: {
  cidrBlock: exampleCidrBlock,
  region: AWS.Us-west-2

exampleCidrBlock: ""

You could add @override to the exampleCidrBlock binding, between the colon and the value:


import Fugue.AWS as AWS
import Fugue.AWS.EC2 as EC2

exampleVpc: {
  cidrBlock: exampleCidrBlock,
  region: AWS.Us-west-2

exampleCidrBlock: @override ""

Then, you can call lwc with the --set option. Include the binding you want to change, along with its new value, in quotes:

lwc --set "exampleCidrBlock: ''" MyVpc.lw

If no output is returned, lwc has successfully compiled your composition with the overridden value. But if you want visual confirmation that the values have been overridden, you can use the following command to compile the composition with the simple semantic backend, producing JSON output (which we pipe into jq):

lwc --set "exampleCidrBlock: ''" MyVpc.lw -s simple | jq .

And here is an excerpt of that output, indicating that the CIDR block is now "":

      "tag": "",
      "value": {
        "enable_dns_hostnames": false,
        "enable_dns_support": true,
        "cidr_block": "",
        "region": "Fugue.Core.AWS.Common.Us-west-2",
        "dhcp_options": "&e736595a-0041-57d5-bd0a-b42928b2ae42"