---
# System prepended metadata

title: FTL Primitives
tags: [docs]

---

# FTL Primitives

This document describes the primitives provided by FTL. These primitives can be composed

# Errors

Errors are first-class data structures explicitly returned from every function using language-specific idioms.

> **NOTE:** Errors are omitted from the abstract representations below for clarity.

# Verbs, sources, and sinks

These are the function primitives of FTL.

## Verbs

Verbs take a single value and return a single value or an error.

```
F(X) -> Y
```

<details>
<summary>Code</summary>

```go
func F(ctx context.Context, x X) (Y, error) {
  // ...
}
```

</details>

## Sources

Sources are functions that return a single value and accept no parameters.
Common use cases for sources are providing data from a queue or external system.

```
F() -> Y
```

<details>
<summary>Code</summary>

```go
func F(ctx context.Context) (Y, error) {
  // ...
}
```

</details>

## Sinks

Sinks are functions that accept values but return nothing. They will typically
have some side-effect such as delivering to a queue or external system.

```
F(X)
```

<details>
<summary>Code</summary>

```go
func F(ctx context.Context, req X) error {
  // ...
}
```

</details>

# Messaging patterns

## Synchronous

A synchronous call to F(X) -> Y executes the function and blocks the caller until the
result or an error is returned.

```
F(X) -> Y
```

<details>
<summary>Code</summary>

```go
func F(ctx context.Context, req X) (Y, error) {
  // ...
}

func G(ctx context.Context, x X) (Y, error) {
  // Synchronously call another verb.
  if y, err := ftl.Call(ctx, F, x); err != nil {
    return VerbResponse{}, err
  }
  // ...
}
```

</details>

## PubSub

PubSub in FTL is comprised of four functions:

1. A (sink) topic T(X) that messages can be published to.
2. One or more (source) subscriptions S^n^() -> X for each topic. Each
   subscription is guaranteed to return the next message from the topic.
3. One or more subscribers F^n^(X) for each subscription.
4. A single, optional user-defined function F(E) for handling
   failed messages. This may be a dead letter topic.

Other notes:

- A message of type X may be published to a PubSub topic T.
- An arbitrary number of subscriptions can be created for a topic.
- Multiple functions can be configured to consume from a single subscription, first-come first-served.
- FTL PubSub is implemented on top of a Kafka-like event log.
  - Different topologies are just different combinations/configurations of topic retention and subscriptions.
  - A subscription is a cursor over the topic's event log.
- Other asynchronous messaging patterns such as callbacks can be implemented on
  top of PubSub.
- Batching can be achieved by defining topics/subscribers that accept a slice of X.

<details>
<summary>Code</summary>

Declaring a Topic:

```go
var T = ftl.RegisterTopic[X]("topic_x") // Returns a Topic[X]
```

Creating and subscribing to a subscription:

```go
var S Subscription[X] = ftl.RegisterSubscription(T, "subscription_x", F)

//ftl:sink
func F(ctx context.Context, x X) error {
  // ...
}

```

Publishing to a topic

```go

//ftl:verb
func Verb(ctx context.Context, x X) error {
  if err := ftl.Publish(ctx, T, x); err != nil {
    return Y{}, err
  }
  // ...
}
```

</details>

### Fanout

In the fanout topology, a copy of each message published to a topic is received
by every subscriber. For this pattern, a separate subscription `Sn` exists for
each subscriber `Fn`:

```
T(X0) ->
  S0(X0)
    -> F0(X0)
  S1(X0)
    -> F1(X0)
...
T(X1) ->
  S0(X1)
    -> F0(X1)
  S1(X1)
    -> F1(X1)
  ...
```

<details>
<summary>Code</summary>

```go
var T = ftl.CreateTopic[X]("T")

var S0 = ftl.Subscription(T, "S0", F0)

var S1 = ftl.Subscription(T, "S1", F1)

//ftl:sink
func F0(ctx context.Context, msg T) error {
  // ...
}

//ftl:sink
func F1(ctx context.Context, msg T) error {
  // ...
}
```

</details>

### First-come first-served

In the first-come first-served topology, a single subscription exists for each
topic and each message published to a topic is sent to the next available
subscriber.

Given a single subscription and two subscribers F0 and F1, this might look like:

```
T(X0) -> S(X0) ->
    F0(X0)
```

```
T(X1) ->
  S(X1) ->
    F1(X1)
```

```
T(X2) ->
  S(X2) ->
    F1(X2)
```

<details>
<summary>Code</summary>

```go
var T = ftl.CreateTopic[X]("T")

var S = ftl.CreateSubscription(T, "S", F0, F1)

//ftl:sink
func F0(ctx context.Context, msg T) error {
  // ...
}

//ftl:sink
func F1(ctx context.Context, msg T) error {
  // ...
}
```

</details>
