Stateful Functions gives Flink the addressing model of actors and the runtime of serverless
Apache Flink Stateful Functions
At a glance
- What is it?
- Apache Flink Stateful Functions is an API for distributed stateful applications where each entity is a virtual function instance addressed by type and ID, with state kept next to the logic and a runtime that separates physical compute from state access. The README points newcomers to a playground repository rather than to the code.
- Who is it for?
- Adopt Stateful Functions if you are already on Flink and your problem is many independent entities with their own state, and you want them to run on Kubernetes or a FaaS platform without giving up consistent state. Do not adopt it if your processing is a pipeline over an event stream, because the DataStream API already models that and Stateful Functions adds an addressing model you do not need.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 161 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The abstraction: four primitives and an address
Stateful Functions is an API that simplifies the building of distributed stateful applications with a runtime built for serverless architectures. The README describes it as bringing together the benefits of stateful stream processing, the processing of large datasets with low latency and bounded resource constraints, along with a runtime for modeling stateful entities that supports location transparency, concurrency, scaling and resiliency.
An application is made of four primitives. Stateful functions are the logic. Ingresses are how events arrive. Routers decide which function instance handles an event. Egresses are how events leave.
A stateful function is a small piece of logic invoked through a message. Each one exists as a uniquely invokable virtual instance of a function type, and each instance is addressed by its type and a unique ID string within that type.
That addressing is the whole idea. A stateful function may be invoked from an ingress or from any other stateful function, including itself, and the caller only needs to know the address of the target. There is no graph of the flow, which is the difference from Flink's own DataStream API, and the README makes that comparison explicit: if you know DataStream, think of stateful functions as a bit like a lightweight KeyedProcessFunction, where the function type is the process function transformation and the ID is the key. The difference is that functions are not assembled in a Directed Acyclic Graph defining the streaming topology, but rather send events arbitrarily to all other functions using addresses.
So this is an actor model with an HTTP-shaped addressing scheme, and the reason it exists is that the actor model and Flink's pipeline model are genuinely different shapes of program.
Why the instances are virtual, and what that buys
Function instances are virtual, because they are not all active in memory at the same time.
At any point in time, only a small set of functions and their state exists as actual objects. When a virtual instance receives a message, one of the objects is configured and loaded with the state of that virtual instance and then processes the message. Similar to virtual memory, the state of many functions might be swapped out at any point in time.
That analogy is doing real work in the design. If you have a million customer entities and a thousand are active in a given window, you need a thousand state objects, not a million, and the mapping from entity to state has to be exact and cheap. Virtual instances are how the framework gets that.
Each virtual instance has its own state, accessed in local variables, and that state is private and local to that instance. The private part is the other half of the model. Because a function only ever touches its own state, there is no shared mutable state to reason about and no lock to take, which is what makes the concurrency story work.
The state access is also not something you write by hand. The runtime's design principles say messaging, state access and updates and function invocations are managed tightly together, and that this ensures a high level of consistency out of the box. So the framework, not the application, decides when a function's state is loaded, and the application just reads local variables.
That is the difference between Stateful Functions and a hand-rolled actor layer on top of a stream processor. The consistency guarantee is a property of the runtime, and that is what you are buying when you adopt it.
The runtime's three principles, and what each one changes
The runtime is built on Apache Flink, and the README lists three design principles that explain the rest of the system.
The first is logical compute and state co-location. Messaging, state access and updates and function invocations are managed tightly together.
The second is physical compute and state separation. Functions can be executed remotely, with message and state access provided as part of the invocation request, and this way functions can be managed like stateless processes and support rapid scaling, rolling upgrades and other common operational patterns.
The third is language independence. Function invocations use a simple HTTP or gRPC-based protocol so that functions can be easily implemented in various languages.
The second and third principles together are the operational story. If a function can be executed remotely with its state supplied as part of the request, then a function is not pinned to a JVM, and a rolling upgrade becomes a matter of replacing the processes that host them. And if the invocation protocol is HTTP or gRPC rather than a Java interface, then the choice of language for a given function is a per-function decision rather than a per-application one.
The repository layout shows that last point concretely. There are separate statefun-sdk directories for Java, Go, JavaScript and Python, plus statefun-sdk-protos for the protocol definitions and statefun-sdk-embedded for embedding. The primary language of the repository is listed as Java, but that is the implementation language of the runtime, not a restriction on what you write functions in.
The README is direct about the deployment target: this makes it possible to execute functions on a Kubernetes deployment, a FaaS platform or behind a micro-service, while providing consistent state and lightweight messaging between functions.
Ingresses, routers and egresses, and the module boundary
Ingresses are the way events initially arrive in a Stateful Functions application, and the README is generous about what qualifies: message queues, logs or HTTP servers, anything that produces an event to be handled by the application.
Routers are attached to ingresses to determine which function instance should handle an event initially. That is the routing decision, and it is where the addressing model meets the outside world. Ingress produces an event, the router decides the address, and the addressed function instance picks it up.
Egresses are a way to send events out from the application in a standardized way. The README adds something worth noticing: egresses are optional, and it is also possible that no events leave the application and functions sink events or directly make calls to other applications. So the framework does not insist on a bidirectional contract between your application and the world.
Modules are the extension mechanism. A module is the entry point for adding the core building block primitives to an application, and a single application may be a combination of multiple modules, each contributing a part of the whole.
The reason the README gives for this is organisational rather than technical: this allows different parts of the application to be contributed by different modules, for example one module may provide ingresses and egresses while other modules may individually contribute specific parts of the business logic as stateful functions. This facilitates working in independent teams, but still deploying into the same larger application.
That is a real constraint on how you structure a team around the framework, and it is the one that shows up in practice. A module boundary that follows the function type rather than the team produces a lot of small modules; a boundary that follows the team produces modules that each depend on the others' function types.
Getting started means going to the playground, not to this repository
The README is unusually direct about where a newcomer should start. It highly recommends starting from the tutorials and examples in the Stateful Functions Playground repository, because there you will find material that serves as a great starting point if you have just started getting to know the project, or are looking for specific examples of common usage patterns.
For Java users there are two named entry points in that playground: the Java SDK Showcase and the Java Greeter Example. The README also gives a command line route, describing it as executing the following commands to clone the playground repository locally.
$ giThat line is where the README text available here is cut off, so the actual clone command is not visible in this copy of the file, and you should read it from the README itself rather than guess at it.
There are other pointers too. The README points at the Stateful Functions Playground repository, and at the official docs at ci.apache.org for fully detailed documentation. The README itself is described as a brief walkthrough on the core concepts and how to set things up to get started, which is an accurate description and also a warning not to treat it as a reference.
The repository top level explains what is actually in the framework. There is statefun-flink for the runtime on Flink, statefun-kafka-io and statefun-kinesis-io for connectors, the four language SDKs, statefun-sdk-protos for the protocol, statefun-shaded for the relocated dependencies, statefun-testutil and statefun-e2e-tests for testing, plus docs/, licenses/, tools/ and a pom.xml at the top level.
That listing is the honest answer to the question of what this repository is. It is the framework and its runtimes, and the working examples live somewhere else.
Where Stateful Functions is the wrong tool
Three cases, and the first one is the most common.
If your problem is a stream pipeline, use the DataStream API. The README itself frames Stateful Functions as a bit like a lightweight KeyedProcessFunction, and the difference it names is that functions are not assembled in a DAG defining the flow. If you have a stream of events, a set of transformations and a sink, the DAG model is the one your problem has, and adopting an actor-style addressing model on top adds indirection without buying anything. Stateful Functions is for the case where the natural unit of your problem is an entity that has its own state and receives messages, such as a shopping cart, a session, or a device.
The second is a single-process application that does not need Flink. The runtime is built on Apache Flink, and the entire value proposition is location transparency, concurrency, scaling and resiliency across a cluster. If the state fits in one process and one process is enough, the operational cost of running a Flink cluster is not repaid.
The third is a hard real-time or ultra-low-latency path. The README's claim is low latency with bounded resource constraints for stateful stream processing, which is a real and useful property, but the design assumes state can be swapped in and out. An access pattern that touches state on every event at high frequency is exactly the case where that design has the most work to do, and the README does not describe latency characteristics or per-invocation costs.
There is also a project-level fact to weigh. The repository is not archived and the last push was on 2026-05-15, and it has no GitHub releases. The README links to the Flink homepage and the project sits under the Apache Flink umbrella, which is a sign of long-term stewardship.
Editorial conclusion
Adopt Stateful Functions if you are already on Flink and your problem is many independent entities with their own state, and you want them to run on Kubernetes or a FaaS platform without giving up consistent state. Do not adopt it if your processing is a pipeline over an event stream, because the DataStream API already models that and Stateful Functions adds an addressing model you do not need. Verify first which SDK you will use, since the repository ships Java, Go, JavaScript, Python and embedded SDKs, and start from the playground repository the README recommends rather than from the framework source.
Frequently asked questions
What is Apache Flink Stateful Functions?
It is an API for building distributed stateful applications with a runtime built for serverless architectures. It combines stateful stream processing, low latency with bounded resource constraints, with a runtime for modeling stateful entities that supports location transparency, concurrency, scaling and resiliency.
What are the four primitives of a Stateful Functions application?
Stateful functions, which hold the logic, ingresses, which are how events initially arrive, routers, which are attached to ingresses to determine which function instance handles an event, and egresses, which are a standardized way to send events out and are optional.
How does Stateful Functions differ from the Flink DataStream API?
The README compares stateful functions to a lightweight KeyedProcessFunction, where the function type is the process function transformation and the ID is the key. The difference is that functions are not assembled in a Directed Acyclic Graph that defines the flow of data, but rather send events arbitrarily to all other functions using addresses.
Which languages can Stateful Functions be written in?
Function invocations use a simple HTTP or gRPC-based protocol so functions can be implemented in various languages, and the repository carries statefun-sdk directories for Java, Go, JavaScript and Python, plus statefun-sdk-embedded and statefun-sdk-protos.
Where should I start with Stateful Functions?
The README highly recommends the tutorials and examples in the Stateful Functions Playground repository, and for Java points at the Java SDK Showcase and the Java Greeter Example. The framework repository itself is a walkthrough of core concepts and setup rather than a usage reference.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/apache-flink-statefun)Was this useful?