# Apache Libcloud: one API across five resource namespaces, and a CI job that publishes prices

> A Python library that hides cloud provider differences, organised by resource type rather than by provider, with a documented policy naming the last release series for every Python version it has dropped, and an automated workflow that publishes a pricing dataset to object storage.

**apache/libcloud** — Apache Libcloud is a Python library that hides differences between different cloud provider APIs and allows you to manage different cloud resources through a unified and easy-to-use API.

- Repository: https://github.com/apache/libcloud
- Website: https://libcloud.apache.org
- Stars: 2,125 · Forks: 931
- Language: Python
- License: Apache-2.0
- Published: 2026-09-30 · Updated: 2026-09-30 · Language: en
- Canonical page: https://hysenlabs.com/projects/apache-libcloud

## Organised by resource type, so the provider is a parameter

The library is divided into five namespaces, one per resource category, and the names are the architecture: 

```bash
libcloud.compute.*
libcloud.storage.*
libcloud.loadbalancer.*
libcloud.dns.*
libcloud.container.*
```

Compute covers cloud servers and block storage, storage covers object storage and content delivery, load balancer covers load balancers as a service, DNS covers DNS as a service, and container covers container virtualisation services. The README names Amazon EC2 and Rackspace Cloud Servers for compute, and Amazon S3 and Rackspace CloudFiles for storage, which dates the project's origin without saying so: those are the two providers a multi-cloud abstraction was first built to reconcile. The consequence of organising by resource rather than by provider is that the abstraction is a lowest common denominator. A call that exists on every compute provider lives on the compute base class, and anything specific to one provider exists only on that provider's driver. So there is a clean answer to the question every user of a multi-cloud library eventually asks: your portable code cannot use the provider's distinctive features, and the moment you write against a driver you have chosen a provider. That is not a defect, it is what a unified interface means, and this library is unusually honest about the trade because the namespace structure makes it visible from the first import. The top-level listing reinforces the shape, with one example script per category: example_compute.py, example_container.py, example_dns.py, example_loadbalancer.py and example_storage.py. Five namespaces, five starting points.

## The Python floor is documented as a table of last-known-good versions

The compatibility section is the best-written part of this README, and it does something few projects do. Rather than saying which versions are supported, it says which are not and, for each one, the last release series that still worked. Python 2.7 and 3.4 were supported through the v2.8.x series. Python 3.5 through v3.4.x. Python 3.6 through v3.6.x, with support dropped in v3.7.0. Python 3.7 and 3.8 through v3.8.x, dropped in v3.9.0. Python 3.9 through v3.9.x. The current floor is Python 3.10 or later, with PyPy 3.10 also supported, and Pyjion named as an option on 3.10. That list is a gift to anyone with a legacy runtime, because it turns a vague question into an arithmetic one. If you are on Python 3.9 you pin the 3.9 series and stop, and you know that without reading a changelog. It also documents a policy rather than an accident: each drop is tied to a specific release, so the removal is a decision with a date rather than a slow drift. The current floor of 3.10 is worth noting as the cost side of that policy, since a library that drops 3.9 on schedule eventually asks you to move too. PyPy and Pyjion being named is another signal that the project tests on more than CPython, which matters more for a library holding network connections than it would for most.

## A workflow that publishes pricing.json to object storage

The most interesting thing in this repository is a badge pointing at a job whose name is the whole description. Among the GitHub Actions workflows listed in the README are a main workflow, a separate integration tests workflow, and one named for publishing pricing.json to an S3 bucket. So this project maintains a pricing dataset as a generated artefact, refreshed by continuous integration rather than by hand. That is a substantial and underappreciated piece of infrastructure for a cloud abstraction library, because the abstraction hides the API but not the cost. A unified interface tells you that creating an instance is one call everywhere; it does not tell you what that instance costs, and cost is the thing that differs most and changes most often. Providers repackage instances, rename classes and shift prices constantly, so a hand-maintained price table is stale within weeks. Publishing it from CI means the data is regenerated on a schedule and served from object storage as a public read-only blob, which is cheap to host and cheap to cache. The practical question for an adopter is whether that endpoint is stable and documented, because the README mentions the workflow but not the file format, and building a cost estimate on an undocumented feed is a dependency you have to verify. Two related items sit in the same header: an OpenSSF Best Practices badge and a Repology badge, both of which track the package across distributions rather than describing the code.

## Unit tests and provider tests are separate workflows, and the second one needs credentials

Three workflows in the header, and the split is informative. There is a main workflow for the ordinary build, and a separate integration tests workflow, which is the arrangement every multi-cloud library converges on because the test problem here is structural. You cannot call a hundred provider APIs on every commit without credentials, without cost, and without being rate-limited into flakiness. So the provider-facing tests live somewhere that can hold secrets and run on a schedule, and the ordinary workflow runs the rest. The integration/ directory in the top-level listing is where those tests live, and tox.ini is what would let them be run across environments locally. Two details about how the project is verified otherwise. There is a coverage badge wired to codecov with a .codecov.yml, and a .ratignore, which is the exclusion list for the foundation licence audit, meaning vendored or generated files are declared rather than quietly skipped. The example scripts at the root double as the smallest possible test of the public surface: if example_dns.py stops running, the DNS namespace is broken. That is a cheap and effective arrangement for a library whose failure mode is an API that changed shape underneath it.

## Four linters, a formatter, and a repository written in reStructuredText

The toolchain in this project is broad, and reading it tells you about the project's age and its priorities. For formatting there is a black badge and a .pre-commit-config.yaml, so style is enforced on commit rather than in review. For linting there is a .flake8 file and a pylint_plugins directory, the second being the more interesting one, because custom plugins for a linter usually mean the project has domain rules that the general-purpose linter cannot know. For environments there is tox.ini, and for dependency resolution a uv.lock, so a project that predates uv still resolves through it. That is four or five tools for static analysis, which is a lot of surface for a library whose code is mostly provider drivers, but it is also the residue of a long-lived foundation project that modernised in place rather than being rewritten. The documentation side has the same character. The README is README.rst, written in reStructuredText with image directives rather than in Markdown, and there are CONTRIBUTING.rst and CHANGES.rst alongside it. The website lives in a separate repository, apache/libcloud-site, and the docs are built on Read the Docs with a .readthedocs.yml. So the prose in this project is part of a documentation toolchain rather than something written for a terminal, which explains the field lists and the reference-style links at the bottom.

## Not infrastructure as code, and not a way to reach everything

Two misunderstandings are worth heading off. The first is that Libcloud declares infrastructure. It does not. It is a client library that makes API calls, and it has no notion of a desired state, no plan, no drift detection and no dependency graph between resources. A script using it creates things in the order the author wrote, and if the script fails halfway, the half that succeeded is still there. If you want declarative infrastructure management, this is the wrong tool, and the ecosystem has several right ones. The second is coverage. Five namespaces is a real amount of surface, and it is a snapshot of the cloud as it looked when a category was added. There is no namespace for serverless functions, for a managed message queue, for a modern data warehouse, for object storage with a table interface, or for the configuration and secrets services that most production systems need. Those exist in every provider and none of them is here. So the honest scope statement is: Libcloud covers the classic compute, storage, load balancing, DNS and container resources across many providers, and nothing else. For code that must span providers today, that is a well-chosen slice. For code that spans a modern platform, you will be writing provider-specific clients beside it, and at that point you are paying for the abstraction without using it.

## Conclusion

Adopt Libcloud if you genuinely need to run the same code against more than one provider, because that is the only case where the abstraction pays for itself, and its compatibility policy is the best argument for it: the README names the last release series supporting every Python version it has dropped, so you can compute the exact version to pin for a legacy runtime instead of guessing. Do not adopt it on a single provider, where the abstraction removes access to that provider's distinctive features, and do not read it as infrastructure as code, because it is a client library that makes calls rather than a tool that declares desired state. Three things to check first. The provider-specific surface is reachable only through a driver, so code written against the base classes will not use it. The pricing dataset is maintained by an automated workflow that publishes to object storage, so verify the endpoint and format before you build a cost estimate on it. And note that the release history visible in the repository is thin, so pin a version from the package index and read CHANGES.rst rather than tracking trunk.

## FAQ

### How do I install Apache Libcloud and what Python version does it need?

The package is published on PyPI as apache-libcloud, and the README states support for Python 3.10 or later and PyPy 3.10 or later, with Pyjion named as an option on 3.10. Classifiers list Python 3.10 and 3.11 among the targeted versions.

### Which Python versions has Apache Libcloud dropped, and which version was the last to support them?

The README names a last release series for each: v2.8.x for Python 2.7 and 3.4, v3.4.x for 3.5, v3.6.x for 3.6, v3.8.x for 3.7 and 3.8, and v3.9.x for 3.9. Support for 3.9 has been dropped, and the current floor is Python 3.10.

### What resource types does Apache Libcloud support?

Five namespaces: compute for cloud servers and block storage, storage for object storage and content delivery, loadbalancer for load balancers as a service, dns for DNS as a service, and container for container virtualisation. There is a matching example script at the repository root for each one.

### Does Apache Libcloud maintain cloud pricing data?

The repository carries a GitHub Actions workflow for publishing pricing.json to an S3 bucket, so pricing is generated and published automatically. The README names the workflow but does not document the file format or the endpoint.

### Is Apache Libcloud an infrastructure as code tool?

No. It is a client library that makes provider API calls through a unified interface. It declares no desired state, plans nothing and detects no drift, and its coverage is limited to the five resource namespaces listed in the README.

## Sources

- [apache/libcloud on GitHub](https://github.com/apache/libcloud)
- [Issues](https://github.com/apache/libcloud/issues)
- [License: Apache-2.0](https://github.com/apache/libcloud/blob/trunk/LICENSE)
- [Project website](https://libcloud.apache.org)
- [README](https://github.com/apache/libcloud/blob/trunk/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/apache-libcloud
