{"id":39100077,"url":"https://github.com/ddanier/fastapi-module-loader","last_synced_at":"2026-03-08T22:02:22.945Z","repository":{"id":184689651,"uuid":"485287841","full_name":"ddanier/fastapi-module-loader","owner":"ddanier","description":"FastAPI Module handling (like Django AppConfig)","archived":false,"fork":false,"pushed_at":"2026-02-09T21:16:12.000Z","size":128,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-02-25T07:34:44.242Z","etag":null,"topics":["fastapi","modules","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ddanier.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-04-25T08:36:57.000Z","updated_at":"2026-02-09T21:16:15.000Z","dependencies_parsed_at":"2024-03-28T18:57:37.683Z","dependency_job_id":"2928bd0a-842a-4ff4-bbc2-f560a7781660","html_url":"https://github.com/ddanier/fastapi-module-loader","commit_stats":null,"previous_names":["team23/fastapi-module-loader","team23/fastapi-module-loading"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/ddanier/fastapi-module-loader","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddanier%2Ffastapi-module-loader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddanier%2Ffastapi-module-loader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddanier%2Ffastapi-module-loader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddanier%2Ffastapi-module-loader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ddanier","download_url":"https://codeload.github.com/ddanier/fastapi-module-loader/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddanier%2Ffastapi-module-loader/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30205893,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T19:07:06.838Z","status":"online","status_checked_at":"2026-03-07T02:00:06.765Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fastapi","modules","python"],"created_at":"2026-01-17T19:03:46.935Z","updated_at":"2026-03-08T22:02:22.939Z","avatar_url":"https://github.com/ddanier.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `fastapi-module-loader`\n\nThis library allows you to load modules in a structured and well defined way. The overall idea is explained pretty\nquick, we have a list of modules and then ensure all those are basically imported. Also we allow the module classes to\nexecute additional code on loading. This is useful to for example resolve forward references with pydantic, to register\nsome hooks or just load all SQLAlchemy ORM models so relationships work.\n\nThe module loader idea is based on what Django does using `AppConfig`'s - so if you know those you might find this\npretty straight forward.\n\n# Example FastAPI setup\n\nLets say we are using the following folder structure in your project, `modules` may contain a list of modules\nused by your application:\n\n```text\nyourapp\n|-- modules\n|   `-- something\n|       `-- __init__.py     \u003c- SomethingModule is defined here, see technical details below\n|-- config.py               \u003c- Your config file\n|-- loader.py               \u003c- This is where you put the global loader instance\n`-- main.py                 \u003c- Your normal FastAPI application lives here\n```\n\nNow lets put the MODULES list into `config.py`:\n\n```python\nMODULES = [\n    \"yourapp.modules.something.SomethingModules\",\n]\n```\n\nThen add the loader to your `loader.py`:\n\n```python\nfrom fastapi_module_loader import ModuleLoader\n\nfrom yourapp.config import MODULES\n\n\nloader = ModuleLoader(MODULES)\n```\n\n**Note:** We are **NOT** calling `loader.load()` or `loader.setup()` here. This is because we want to do this in our\n`main.py` file so we have control when this actually happens.\n\nThen change your `main.py` to look like this:\n\n```python\nfrom fastapi import FastAPI\n\nfrom yourapp.loader import loader\n\n\n@asynccontextmanager\nasync def lifespan(app: FastAPI):\n    loader.setup()  # Setup everything on FastAPI startup\n    yield\n\n\nloader.load()  # Ensure everything is loaded\napp = FastAPI(lifespan=lifespan)\n\n# ...put the actual FastAPI code here\n```\n\n# Use cases\n\nThose are some use cases we encountered while working on projects. Those use cases led us to create this library:\n\n* `main.py`: Load the modules to ensure everything is setup for the FastAPI app.\n* In alembic migrations `env.py`: Ensure all `orm.py` are loaded and the alembic migrations can \"see\" all the ORM\n  models. Otherwise, detecting any changes would not be possible at all.  \n  (see https://alembic.sqlalchemy.org/en/latest/tutorial.html#the-migration-environment)\n* To register any hooks bound to `async-signals` Signal instances.  \n  (see https://github.com/team23/async-signals)\n* There will be many additional use cases for using the module loader. If you have any interesting use case please\n  open an issue and tell us about it. 😉\n\n# Technical details\n\n## Basic structure\n\nThe class `ModuleLoader` is the main entry point for the module loader system. It needs to be instantiated with a\nlist of modules as strings. You have to initialize the module loader in some global place for your application. This\ncan be done directly in `main.py`, although it is recommended to use a separate file for this like `loader.py`.\n\nGetting you own loader instance can look like this:\n```python\nfrom fastapi_module_loader import ModuleLoader\n\n\n# We recommend putting the module list into your normal config file - if you have one\nMODULES = [\n    \"yourapp.modules.something.SomethingModules\",\n    \"yourapp.modules.something_else.SomethingElseModules\",\n    \"yourapp.modules.etc.EtcModules\",\n]\n\n\nloader = ModuleLoader(MODULES)\n```\n\nThe actual loading process then works like this:\n1. Using `loader.load()` will import all the modules passed to the constructor. It will use `importlib` to load the\n   module and then instantiate the module class. After this is done it will call the `load()` method on the modules -\n   you can use this hook to load additional modules or similar.\n2. The `loader.setup()` will execute the `setup()` method of all the modules. This is where the modules should do\n   additional setup work like resolving `ForwardRef`'s or registering hooks.  \n   Note that `loader.setup()` will actually call `pre_setup()`, then `setup()` and finally `post_setup()` on the \n   modules. This allows you to have different stages of your setup process.\n\n## Module structure\n\nA module is a class that inherits from `BaseModule`. It may implement the `setup()` and other methods as hooks. All\nmethods will be called on module loading/setup.\n\nExample for a module:\n\n```python\nfrom fastapi_module_loader import BaseModule\n\n\nclass SomethingModule(BaseModule):\n    def setup(self):  # providing a setup method is optional\n        print(\"Hello world!\")\n```\n\n## Loading process\n\n`loader.load()` will import all the modules and then call the `load()` method on them. This is the place where you\nshould load further modules if you need to.\n\n```python\nfrom yourapp.loader import loader  # Import has to match your own setup\n\n\nloader.load()  # will import all modules and call load() on each of them\n```\n\nWhen all modules are loaded you may use `loader.setup()` to execute the `setup()` method on all modules. This is the\nplace where you should do your actual setup work.\n\n```python\nfrom yourapp.loader import loader  # Import has to match your own setup\n\n\nloader.setup()  # will call pre_setup(), setup() and then post_setup() on all modules\n```\n\n## Loading further modules in `load()`\n\nIt is a very common use case to load further modules in the `setup()` method. To support this use case the `BaseModule`\nclass provides a method `load_in_module()` then will load given module names inside the current module scope.\n\nExample:\n\n```python\nfrom fastapi_module_loader import BaseModule\n\n\nclass SomethingModule(BaseModule):\n    def setup(self):\n        self.load_in_module(\"orm\")\n```\n\nThis will load `yourapp.modules.something.orm` if the module file itself is placed in\n`yourapp/modules/something/__init__.py`.\n\nSee this example structure:\n\n```text\nyourapp\n`-- modules\n    `-- something\n        |-- __init__.py     \u003c- SomethingModule is defined here\n        |-- etc...py\n        |-- orm.py          \u003c- This is loaded\n        `-- etc...py\n```\n\n**Note:** For `load_in_module` to work you are required to put the modules class (`SomethingModule` in this example)\ninto the `__init__.py` file of the module. Otherwise the module loader will not be able to find the module you want\nit to load.\n\n## Integrating the module loader\n\nTo ensure everything is setup properly you should just call the methods mentioned above. This may for example look\nlike this:\n\n```python\nfrom fastapi_module_loader import loader\n\n\nloader.load()\nloader.setup()\n\n\n# Put the actual code here\n```\n\n## Exceptions\n\nThe module loader will raise `ImproperlyConfiguredModules` if anything went wrong during handling the modules and\nloading those, this includes:\n* A module could not be imported\n* A module does not inherit from `BaseModule`\n* You are calling `loader.setup()` when `loader.load()` has not been called before\n\nNote however that all exceptions raised by the `setup()` method of the modules will just be passed through. The module\nloader will not catch now handle them. This is also the case if a modules to be loaded by `Self.load_in_module()`\ndoes not exist. Generally you have to handle those errors in `setup()` yourself.\n\n# Contributing\n\nIf you want to contribute to this project, feel free to just fork the project,\ncreate a dev branch in your fork and then create a pull request (PR). If you\nare unsure about whether your changes really suit the project please create an\nissue first, to talk about this.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddanier%2Ffastapi-module-loader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fddanier%2Ffastapi-module-loader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddanier%2Ffastapi-module-loader/lists"}