The simple & low-maintenance Go distributed actor framework
Francis is a framework and runtime for Distributed Actors (also known as Durable Objects) for Go apps.
With Francis, you can build highly-available apps that scale horizontally and/or use microservices. Unlike other actor frameworks, Francis is designed to be simpler to add to your solution and lower-maintenance: it only requires a relational database (PostgreSQL or SQLite) and can optionally run embedded in your apps too, without a separate control plane service.
What you can use Francis for:
- Build stateful services where each entity (e.g. a user, a device, a shopping cart, a game session) is an actor with its own durable state
- Scale horizontally across many hosts without sharding your data by hand: Francis places each actor on exactly one host and routes calls to it
- Run background work on a schedule with durable alarms that survive restarts
- Add resilience to microservices without standing up extra infrastructure beyond a database
// An actor is just a Go struct that implements one or more methods
func (c *Counter) Invoke(ctx context.Context, method string, data actor.Envelope) (any, error) {
state, _ := c.client.GetState(ctx)
state.Count++
_ = c.client.SetState(ctx, state, nil)
return state.Count, nil
}Francis is fully open source and released under a permissive MIT license.
If you’re new to the distributed actors pattern, this article provides a good starting point.
How it works#
- You write an actor as a Go struct and register it with an actor host under a type name.
- Your app invokes an actor by its type and ID (e.g.
cart/user-42). Francis activates the actor on exactly one host in the cluster and routes the call to it.
Actors implement turn-based concurrency to ensure that they are serving a single request at a time. - The actor reads and writes its own durable state, stored in the database.
While the actor is active, its state is cached in-memory for fast access.
State outlives the actor: when an actor is hibernated and later re-activated (possibly on another host), its state is still there. - Actors can schedule alarms to run work at a future time, optionally on a repeating interval.
Alarms are durable and survive restarts. - After a configurable idle period, an actor is hibernated automatically to free resources. The next call re-activates it.
Key features#
- Virtual actors: actors are addressed by type and ID, activated on demand, and run one invocation at a time, so you never manage their lifecycle or worry about concurrent access to their state.
- Durable state: each actor has its own state persisted in PostgreSQL or SQLite: it survives deactivation, restarts, and moving between hosts.
- Durable alarms: schedule one-off or repeating work that survives process restarts.
- Two topologies, same code: for small clusters, run everything embedded in your app (local) with no extra services. Alternatively, point your workers at a standalone runtime (remote) when you want a dedicated control plane to support a larger number of hosts. Your actor code is identical.
- Low-maintenance: the only hard dependency is a relational database: no separate message broker, no external coordination service.
- Secure by default: hosts authenticate each other with mTLS using certificates derived from a shared cluster key, with pluggable host bootstrap (pre-shared key or JWT)
- Built for Go: a small, idiomatic API familiar to Go developers.
Where to go next#
- New to actors? Start with What is Francis and the core concepts .
- Want to run something now? Follow the Quickstart .
- Ready to write code? See Writing actors .