# How FTL language runtimes work ## Building After the below steps are complete FTL has enough information to deploy the module and the language-specific build stages are complete. ### Extract dependencies The first thing FTL does is a fast pass to [extract imports](https://github.com/TBD54566975/ftl/blob/main/buildengine/deps.go) from the source code. The modules are then built in topological order based on the imports. This process is built into FTL itself. ### Generate dependencies Before building a module, any dependencies must be code-generated somewhere that the language toolchain can load. For example, in Go we generate modules into `${gitroot}/.ftl/go/modules` and use a `go.work` file to pull these into the module's build. The generated code includes all of the public types, functions, and resources for a given module, and is created from the module's schema. The FTL build engine will ensure that the schema protobuf for each module is provided to the language-specific build. ### Extract the schema / build the binary These can be separate steps, but typically they're quite tightly coupled. The FTL tooling expects at least two artefacts to exist after the language-specific tooling has completed its build: 1. A `schema.pb` file containing the encoded [xyz.block.ftl.v1.schema.Module](https://github.com/TBD54566975/ftl/blob/main/backend/protos/xyz/block/ftl/v1/schema/schema.proto) protobuf representing the extracted FTL schema for the module. 2. One or more files needed to execute the module on a Runner. In Go this is a single binary, `main`. FTL defines sane defaults for each language, but they can be overridden in the module's [ftl.toml](https://github.com/TBD54566975/ftl/blob/main/common/moduleconfig/moduleconfig.go) file. #### Schema types FTL has a relatively rich type system, which needs to be fully supported. The full set of types is listed [here](https://tbd54566975.github.io/ftl/docs/reference/types/). #### Schema symbol naming To ensure consistent naming of symbols across languages, FTL normalises casing to the following: 1. Types are `UpperCamelCase` 2. Functions are `lowerCamelCase` Acronyms/initialisms are never all-caps, eg. `Dns` not `DNS`. The algorithm for normalising case is defined in code [here](https://github.com/TBD54566975/ftl/blob/main/backend/schema/strcase/case.go), but is basically: Split before the start of any upper case run, or underscore, dropping underscores. eg. | Symbol | Tokens | Normalised | | ---------------- | -------------------------- | ----------------- | | `"TwoWords"` | `["Two", "Words"]` | `"twoWords"` | `"two_words"` | `["two", "words"]` | `"twoWords"` | `"twoWORDSMore"` | `["two", "WORDS", "More"]` | `"twoWordsMore"` > [!Note] > Similarly, when _generating_ code, FTL will use the idiomatic casing of the language. As an end-to-end example, given the Python function `my_awesome_verb()`, the FTL verb name would be `myAwesomeVerb` and the Go function name would be `MyAwesomeVerb`. ## Runtime In order to integrate with FTL, each language also needs a runtime. At a minimum, the runtime needs to implement inbound and outbound verb calls: 1. The gRPC endpoint [VerbService.Call()](https://github.com/TBD54566975/ftl/blob/main/backend/protos/xyz/block/ftl/v1/ftl.proto#L99) in order to receive calls. 2. A function in an FTL package or on an FTL-specific context object, that allows the runtime to call other verbs via a `VerbService.Call()` client. The RPC client should connect to the VerbService running at the URL passed through the environment variable `$FTL_ENDPOINT` (eg. `FTL_ENDPOINT=http://127.0.0.1:8892`). The FTL Runner will ensure this environment variable is set. ### Payload encoding FTL currently encodes all request/response payloads as JSON.