The official Python implementation of the Firefly Framework

pyFly

Spring Boot's cohesion, native to async Python.

Build production-grade microservices with the patterns you trust — dependency injection, CQRS, event-driven architecture, sagas, event sourcing — all integrated, all consistent, with production-ready defaults from the first commit.

$ curl -fsSL https://raw.githubusercontent.com/fireflyframework/fireflyframework-pyfly/main/install.sh | bash
Python 3.12+ Apache 2.0 mypy strict async-first v26.06.113
39Modules
5Layers
18Book Chapters
Apache 2.0Open Source

Why PyFly

Python gives you infinite choice.
What it doesn't give you is cohesion.

Every new service starts with two weeks of decisions — web framework, ORM, message broker, DI wiring, project layout. Six months later a second team makes entirely different choices. Now you have two codebases with nothing in common. PyFly makes these decisions for you — one cohesive, full-stack programming model where every module is designed to work together.

01

One cohesive stack

DI, HTTP, data, messaging, caching, security, observability — integrated, consistent, and wired automatically. No bespoke glue.

02

Not a port — native

The same enterprise model Firefly proved on Spring Boot (40+ Java modules), reimagined for async/await, type hints, and Protocols.

03

Familiar to Spring devs

Stereotypes, auto-configuration, Spring-Data repositories, actuator. A Spring-parity callout at every turn.

No boilerplate. No manual wiring.

Write the logic. PyFly wires the rest.

The DI container resolves dependencies from type hints, validates request bodies, and publishes domain events — all out of the box. Same model, whether you're building a controller, a CQRS bus, or a distributed saga.

from pyfly.container import rest_controller, service
from pyfly.web import request_mapping, post_mapping, Body, Valid

@service
class OrderService:
    def __init__(self, repo: OrderRepository, events: EventPublisher) -> None:
        self._repo = repo
        self._events = events

    async def place_order(self, order: Order) -> Order:
        saved = await self._repo.save(order)
        await self._events.publish(OrderPlaced(order_id=saved.id))
        return saved

@rest_controller
@request_mapping("/orders")
class OrderController:
    def __init__(self, service: OrderService) -> None:
        self._service = service

    @post_mapping("", status_code=201)
    async def create(self, order: Valid[Body[Order]]) -> Order:
        return await self._service.place_order(order)
from pyfly.cqrs import command, query, CommandHandler, QueryHandler

@command(CreateUser)
class CreateUserHandler(CommandHandler[CreateUser, int]):
    def __init__(self, repo: UserRepository) -> None:
        self._repo = repo

    async def handle(self, cmd: CreateUser) -> int:
        return (await self._repo.save(User(name=cmd.name, email=cmd.email))).id

@query(FindUserById, cache_ttl=60)  # caching composes declaratively
class FindUserByIdHandler(QueryHandler[FindUserById, User]):
    def __init__(self, repo: UserRepository) -> None:
        self._repo = repo

    async def handle(self, q: FindUserById) -> User:
        return await self._repo.find_by_id(q.user_id)

# Dispatch — buses are auto-wired by the CqrsAutoConfiguration entry point
user_id = await commands.dispatch(CreateUser(name="Ada", email="ada@example.com"))
user = await queries.dispatch(FindUserById(user_id=user_id))
from pyfly.transactional.saga import saga, saga_step
from pyfly.transactional.saga.core.context import SagaContext

@saga(name="place-order", timeout_ms=30_000)
class PlaceOrderSaga:
    # `compensate=` names a method to invoke if a later step fails.
    @saga_step(id="reserve-inventory", retry=3, backoff_ms=500, compensate="release_inventory")
    async def reserve(self, ctx: SagaContext) -> str:
        return await self._inventory.reserve(ctx.input["order_id"])

    async def release_inventory(self, ctx: SagaContext) -> None:
        await self._inventory.release(ctx.input["order_id"])

    @saga_step(id="charge-payment", depends_on=["reserve-inventory"], compensate="refund_payment")
    async def charge(self, ctx: SagaContext) -> str:
        return await self._payments.charge(ctx.input["order_id"], ctx.input["amount"])

    @saga_step(id="ship-order", depends_on=["charge-payment"])
    async def ship_order(self, ctx: SagaContext) -> None:
        await self._ship.dispatch(ctx.input["order_id"])

Philosophy

Easy to start. Easy to change. Ready for production.

Convention over Configuration

Production-ready defaults for every module. A complete web service is a few lines of YAML — override only what matters.

Your Code, Not Ours

Business logic never imports sqlalchemy, redis, or aiokafka. Hexagonal ports & adapters keep infrastructure swappable.

Async-Native, Type-Safe

Built for asyncio from the ground up. Every public surface is fully typed and checked by mypy in strict mode.

Production-Ready from Day One

Structured logging, correlation IDs, PII redaction, health checks, Prometheus metrics, OWASP headers, graceful shutdown — the baseline.

Architecture

Cohesive, layered, and hexagonal.

Five layers on an async core. Every external system reached through a Protocol port. The right adapters wired automatically at startup — so you can swap PostgreSQL for MongoDB, or Kafka for RabbitMQ, without touching a line of business logic.

PyFly architecture at a glance: one front door over five layers — Cross-Cutting, Integration, Infrastructure, Application, Foundation — on an async core (asyncio, uvloop, ASGI).
PyFly hexagonal architecture: an application core depending only on Protocol ports, with swappable adapters implementing each port.
Ports & adapters — depend on Protocols, swap implementations freely.
PyFly auto-configuration: entry-point discovery, conditional guards, then bind / fall back / skip.
Auto-configuration — detect installed libraries, bind the right adapters.

Read the architecture guide →

Featured Patterns

More than a web framework.

PyFly ships production-grade implementations of the distributed patterns that power real microservices — each a first-class module with port-and-adapter design, CLI scaffolding, metrics, tracing, and persistence.

PyFly distributed transaction patterns: a saga DAG with reverse-order compensation, alongside Saga, Workflow, and TCC summary cards.

Saga

Distributed transactions with automatic compensation. Parallel DAG execution, per-step retries, idempotency keys, DLQ + recovery.

transactional →

Workflow

Durable, signal-driven orchestration. Wait for signals or timers, spawn child workflows, query while running. Temporal-style, native.

transactional →

TCC

Try / Confirm / Cancel — strong-consistency three-phase transactions for financial workloads where compensation alone isn't enough.

transactional →

Event Sourcing

Append-only event log, aggregates that rebuild from history, snapshots, transactional outbox, projections, upcasting.

eventsourcing →

CQRS

Command/Query buses with validation, authorization, and caching composing declaratively as cross-cutting concerns.

cqrs →

Rule Engine

Externalize business rules in a YAML DSL with AST evaluation, audit trails, batch evaluation, and hot reload.

rule-engine →

Modules

39 modules across 5 layers.

Everything from HTTP routing and database access to distributed transactions, identity, content management, and DDD building blocks.

Foundation
corekernelcontainercontextconfiglogging
Application
webserverdatadata-relationaldata-documentcqrsvalidation
Infrastructure
securitymessagingedacacheclientschedulingresilienceshelltransactionaleventsourcingdomainpluginsrule-engineconfig-server
Integration
idpecmnotificationscallbackswebhooksstarters
Cross-Cutting
aopobservabilityactuatoradmintestingcli

Browse all module guides →

Quickstart

Zero to a running service in under a minute.

  1. 1

    Install the CLI + framework

    curl -fsSL https://raw.githubusercontent.com/fireflyframework/fireflyframework-pyfly/main/install.sh | bash
  2. 2

    Scaffold a REST API with batteries included

    pyfly new my-service --archetype web-api && cd my-service
  3. 3

    Run it — logging, health, metrics & OpenAPI all on by default

    pyfly run --reload
  4. 4

    It's live

    curl http://localhost:8080/health # {"status":"UP"}

    OpenAPI / Swagger UI at http://localhost:8080/docs

The Book

PyFly by Example

The official, project-driven book. Across 18 chapters in five parts it builds Lumen — a real wallet & ledger microservice — from an empty folder into a secured, observable, event-driven service. Every listing is drawn from a running project. Spring developers get a parity callout at every turn.

The Firefly Ecosystem

One programming model across every runtime.

PyFly is the green firefly of the Firefly Framework family — the same cohesive model on Java/Spring Boot, .NET, Rust, Go, and Angular.

The Firefly Framework family: Java/Spring Boot, .NET, PyFly (Python, highlighted), Rust, Go CLI, Angular frontend, and GenAI — all sharing one programming model.

Build production-grade Python apps — from the first commit.