CLI tool
fal-ai/fal avatar
fal-ai/fal

fal is a serverless Python runtime for the code that has to run on demand

⚡ Fastest way to serve open source ML models to millions

973 stars106 forksPythonApache-2.0

At a glance

What is it?
fal is a serverless runtime for Python, and the repository holds the two packages that make it usable, the `fal` package for defining, testing and deploying serverless apps, and `fal-client` for calling model APIs and your own deployed endpoints from Python. The interface is small enough to read in one sitting, a class, a decorated endpoint, and a command that addresses it by file and class name.
Who is it for?
fal suits a team that wants to put a model behind an HTTP endpoint without running a GPU, and that values the difference between testing on a temporary URL and deploying to a persistent one, since both are one command away in the same interface.
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 1 day ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One package to deploy with, one to call with

The repository contains the main Python packages for building on fal, and there are two of them, and choosing wrongly is the most likely first mistake. The `fal` package, in `projects/fal`, is for defining, testing and deploying serverless apps on the platform, and it ships both the Python SDK and a command line tool. The `fal-client` package, in `projects/fal_client`, is for the other direction, calling fal model APIs or your own deployed endpoints from Python. The platform itself is described as a serverless Python runtime that lets you run and scale code in the cloud with no infrastructure management, built for pipelines, for serving machine learning models and for scaling them to many users, with the model that resources scale down to zero when they are not used. The third project in the tree, `isolate_proto`, appears in the source install instructions.

An app is a class with a decorated endpoint

The definition of a serverless app in this system is deliberately small. You subclass `fal.App` and decorate a method with `fal.endpoint`:

python
import fal


class MyApp(fal.App):
    @fal.endpoint("/")
    def run(self) -> dict:
        return {"message": "Hello, World!"}

A path, a method, a return value. The decorator is what turns an ordinary method into something the runtime can address over HTTP, and the return type annotation is how the schema of the response is derived, which is why the example annotates the return as a dict rather than leaving it off. The application class is the unit of deployment, so a file can hold several classes and each one is a separate endpoint with its own route. The two things you must have before any of this works are the package and a login, since the CLI has to authenticate with the platform first, and the documentation gives both as the first two steps of the quick start.

Testing and deploying differ by one word

The same address identifies the app in both cases, and the address format is the interesting detail. It is the file path, then two colons, then the class name:

bash
fal run hello_world.py::MyApp

The `run` command executes the app on the platform for testing, and the documentation describes the SDK as including testing with temporary URLs, so a `fal run` gives you a working endpoint without it being a permanent deployment. The deploy command is the same string with a different verb:

bash
fal deploy hello_world.py::MyApp

The deploy command puts it on a persistent endpoint. Nothing else changes, which is the point of the design, because the difference between experimenting and shipping should be one word rather than a change of configuration. For a team with a code review culture, the file and class addressing has a second benefit, since the thing you deploy is named in a way that points at the source, and the diff that ships is the same diff you wrote.

Calling a model, and calling your own endpoint

The client package is the other half of the loop. It is installed on its own and it needs a key in the environment:

bash
pip install fal-client
export FAL_KEY="your-api-key"

The call takes a model identifier and a set of arguments:

python
import fal_client

result = fal_client.subscribe(
    "fal-ai/flux/schnell",
    arguments={
        "prompt": "a futuristic cityscape at sunset",
        "image_size": "landscape_16_9",
    },
)

print(result["images"][0]["url"])

The result is a dictionary of URLs rather than an image object, which is the shape a web application wants. The same call reaches your own deployed apps, and the documentation says you do that by passing your endpoint identifier where the model identifier was, so the two live in the same position in the same function. That symmetry is what makes a pipeline easy to assemble, since the output of one step is a model identifier and the input of the next is an argument, and no other client library is needed for the parts that are not models.

The container is distroless, and the build is a venv in a slim image

The Dockerfile in the repository is short and shows the runtime philosophy. The build stage starts from a Python 3.11 slim image, creates a virtual environment at `/opt/fal`, copies the `projects` directory to `/src`, and installs the `fal` package from that source into the environment. The runtime stage is `gcr.io/distroless/python3-debian12`, which contains a Python interpreter and almost nothing else, and it receives two things from the build stage, the environment itself and a copy of the build's temporary directory placed under `/usr/local/bin`. The entry point is the installed console script, `/opt/fal/bin/fal`. The result is an image with no shell, no package manager and no build tools in the final layer, which is the right shape for something that runs in a serverless platform where the image is the artefact, and it is also the reason the build stage bothers with a virtual environment at all, since the environment is what gets copied forward.

A monorepo with a docs build that assembles two manuals

The repository layout is a monorepo with a `projects/` directory, a `tools/` directory, the Dockerfile, a Makefile and a pre-commit configuration, plus an `AGENTS.md` for coding agents working in the tree. The Makefile in the root is only about documentation, and it is worth reading because it shows how the two SDKs are published. The `docs` target delegates to the Makefile inside each project to build that project's documentation, then assembles the results into a single tree, creating `docs/_build/html`, copying the `fal` project's output into a `sdk` subdirectory and the `fal_client` project's output into a `client` subdirectory, after clearing the previous `docs` tree. The result is a single documentation site with two manuals side by side, which is the right call when the two packages are read by different people, since one is for the person deploying and the other for the person calling. The version cadence on the releases page is fast, with fal at 1.82.0 on 2026-10-20, 1.81.4 on 2026-10-08 and the isolate protocol package at 0.34.5 on 2026-10-16.

What the platform model means for an adopter

The commercial shape is the thing to understand before writing code, and the README is clear about the two halves of it. fal is a platform with a hosted runtime, a dashboard, a model gallery and a documentation site, and the repository is the client side of that platform rather than the platform itself. So an adopter is accepting a contract with a service, its identifiers, its key handling, its model catalogue and its pricing, and the code in this repository is what makes that contract pleasant to program against. The scaling story is the part that makes the model attractive for the workload the project describes, since resources scale down to zero when they are not used, which suits an endpoint that is called a few times an hour rather than a service that is busy all day. The risks are the usual ones for a managed platform, the cost per call, the rate limits, the model catalogue changing under you, and the fact that a deployment is a hosted endpoint rather than a process you own. The licence itself is Apache-2.0, so the code is not the constraint; the platform dependency is.

Editorial conclusion

fal suits a team that wants to put a model behind an HTTP endpoint without running a GPU, and that values the difference between testing on a temporary URL and deploying to a persistent one, since both are one command away in the same interface. It is a poor fit if you need to own the serving infrastructure, since the platform is the product and the runtime is a contract with it, and it is a poor fit for a workload that is not spiky, since the scaling model is built around usage that goes to zero. Before you commit, check three things: which package you actually need, since `fal` deploys and `fal-client` calls and installing both by default is a common mistake, how the model identifiers and endpoint identifiers differ, since a model id and your own endpoint id go in the same position in the call, and the version you pin, with fal 1.82.0 published on 2026-10-20 under the Apache-2.0 licence.

Frequently asked questions

What is fal?

A serverless Python runtime for running and scaling code in the cloud with no infrastructure management, built for pipelines and for serving machine learning models. This repository holds the main Python packages for building on it, the `fal` package for deploying and the `fal-client` package for calling.

How do I deploy a Python function with fal?

Subclass `fal.App`, decorate a method with `@fal.endpoint("/")`, and run `fal deploy hello_world.py::MyApp` to deploy it to a persistent endpoint, or `fal run hello_world.py::MyApp` to test it with a temporary URL. The address is the file path, two colons and the class name.

How do I call a model with fal-client?

Install `fal-client`, set `FAL_KEY` in the environment, and call `fal_client.subscribe` with a model identifier and an arguments dictionary, for example `fal_client.subscribe("fal-ai/flux/schnell", arguments={"prompt": "..."})`. The result is a dictionary whose values are URLs to the generated media.

Can fal-client call my own deployed fal apps?

Yes, by passing your endpoint identifier where the model identifier would go, so the same function reaches a hosted model or an app you deployed yourself, which is what makes a pipeline of your own endpoints straightforward to assemble.

What is the difference between the fal and fal-client packages?

The `fal` package is the SDK and command line tool for defining, testing and deploying serverless apps, and `fal-client` is the simplest way to call model APIs and deployed endpoints from Python. Installing both is common but usually unnecessary, since most projects need one direction or the other.

Official sources

  1. fal-ai/fal on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/fal-ai-fal.svg)](https://hysenlabs.com/projects/fal-ai-fal)

Was this useful?