🧩 PyFr glues packages into a service

Share
🧩 PyFr glues packages into a service
Photo by Anton Savinov / Unsplash

I built PyFr because production readiness is not a feature of a single package. It is what happens when packages agree on how a service starts, logs, fails, recovers, tests, ships, and documents itself.

PyFr is a cookiecutter template for production-ready Python microservices. The generated service imports no PyFr package. You own the code it writes into your repository.

That distinction matters because the work is not picking an HTTP framework. It is making FastAPI, Pydantic, SQLAlchemy, structlog, OpenTelemetry, Redis, S3, Testcontainers, Docker, CI, and docs work as one system.

🚀 The glue is the product

A service is not just a web app. It is a set of decisions that cut across many libraries:

  • 🧰 how configuration is validated at startup
  • 💥 how errors are represented
  • 🔗 how logs are correlated
  • 📈 how requests are traced end to end
  • 🧠 when database pools open and close
  • 🧯 how graceful shutdown behaves
  • 💚 how health probes answer different questions
  • 🧪 how tests prove the service still works

Each package can solve one piece of that. The service only becomes production-ready when those pieces share one design.

That is why PyFr is a template and not a framework. The product is not an API you call. It is the working combination in your repository.

🛠️ The template also handles the DevOps work

PyFr is not just a code generator. A generated project also gets the operational scaffolding around that code.

It ships a documentation site, CI, release automation, container images, health checks, observability, configuration validation, schema migrations, and tests with real containers. These are not decorative extras. They are the paths you use to build, release, run, observe, and debug the service.

That is part of the glue. Without it, the service still has to be wired by hand into whatever system builds it, runs it, releases it, and watches it in production.

👀 The template keeps the glue visible

A template gives you real code, not a wrapper to configure.

If something breaks, the code you need to read is already in your project. If a part no longer fits, you change it instead of negotiating with an upstream API.

That is also why the template is opinionated. It chooses FastAPI, Pydantic, SQLAlchemy, structlog, OpenTelemetry, Testcontainers, Docker, and conventional tooling. It arranges those packages into layers and keeps the dependency direction explicit.

But the generated output stays yours. You can inspect it, adjust it, or delete the parts you do not need.

♻️ Updating a generated project

The obvious downside of a template is that you own a copy. If a newer version of the template adds a feature or fixes something, a regular template does not give you a clean way to receive that change.

PyFr handles that with a normal git merge. A generated project remembers the template version it came from, and can re-render the newer template using the answers it recorded at generation time. That re-rendered output lands on a pristine template branch, then gets merged into your real project.

Git can tell the difference between a change that came from the template and a change you made yourself. Your customizations stay. Template improvements arrive. If you deleted a file the template originally created, a later update does not resurrect it for you.

That is how PyFr avoids the usual template trap: you own the code, but you are not stranded on the version you generated from.

🚢 What the template ships

The template glues more than runtime dependencies:

  • 🧱 a service that starts and shuts down cleanly
  • 🧾 structured logs and correlation identifiers
  • 🔭 OpenTelemetry instrumentation
  • 💚 health endpoints
  • ⚙️ configuration validation
  • 🗃️ database and cache adapters
  • 🧬 schema migrations
  • 🧪 tests with real containers
  • 🚢 CI, release, docs, and container images

Each one is useful on its own. Together they turn a starting project into a service you can operate.

🤔 Why not a framework

A framework can package one layer. It cannot decide how all of these layers cooperate in your service, because those decisions belong to the applications and teams using them.

PyFr does not try to own that surface. It gives you the working shape, and keeps it in code you can read and change.

Read more