Skip to content

Comments

⚡️ Ensure faster start-up when using many nested routers#10589

Open
jvllmr wants to merge 49 commits intofastapi:masterfrom
jvllmr:deferred-init
Open

⚡️ Ensure faster start-up when using many nested routers#10589
jvllmr wants to merge 49 commits intofastapi:masterfrom
jvllmr:deferred-init

Conversation

@jvllmr
Copy link

@jvllmr jvllmr commented Nov 4, 2023

First of all: Thanks a lot for your on this project! I never thought that Python Web Development (especially for back-ends) could be this much more fun.

Now to the main part: In my FastAPI project I have a lot of nested routers. Because the amount of nested routers I soon reached a FastAPI start-up time of 30 seconds or more. This hurt my developer experience a lot and I soon began digging in to why FastAPI takes so long to load.

After some research I found out that each router calculates all relevant infos on initialization. A router, which includes another router, will re-calculate these values without re-using information from the router it includes. When having a flat project structure this is not a problem.

So the solution was simple: Defer the calculation of values until they are actually needed. By doing that the start-up time was shortened significantly.

One caveat remains: Deferring the calculation results to Exceptions not being raised at start-up and they are only raised at the first call of a route. So they might not be caught if a route is not tested at least once.

This pull request is my proposal to integrate this performance optimization into FastAPI without breaking user space and having to modify tests. I mitigated the Exception's issue by introducing an argument to the APIRouter and APIRoute which decides if values are deferred or not and never deferring values in the top-level (app-integrated) router.

I'm sure there might be a better way. So let me hear if you have suggestions for improvement!

You can find my research and testing environment for this here: https://github.com/jvllmr/fastapi-deferred-init

@Jamim
Copy link
Contributor

Jamim commented Dec 28, 2023

Thanks you, @jvllmr!
This PR and #10546 might perfectly complement each other 🚀

@jvllmr jvllmr reopened this Sep 5, 2024
@jvllmr
Copy link
Author

jvllmr commented Sep 5, 2024

I refactored the pull-request according to the latest changes.

In the meantime the performance improved already (probably because of changes in Pydantic). In my benchmark the median improvement was around 8 to 10x. My benchmark is very simple and there might be more improvement in real world applications.

The tests are failing as of now. I will look into it as soon as I can.

@svlandeg
Copy link
Member

svlandeg commented Sep 6, 2024

Hi @jvllmr!

The tests are failing as of now. I will look into it as soon as I can.

There was an unrelated issue with our CI that is now fixed, so you shouldn't see so many failing tests anymore.

The only test still failing here is the one measuring "coverage" - this basically ensures that all code paths in the code base are tested in our test suite. So, to fix it, it would be good to add a test with this PR that checks the correct behaviour of the new functionality introduced here 🚀

Specifically, when I look at the detailed coverage report, it's the init_routes function that isn't getting properly tested: https://smokeshow.helpmanual.io/6t005p5s2v3j6u064g0q/z_35ba7d295f00afa4_routing_py.html#t1160

@jvllmr
Copy link
Author

jvllmr commented Sep 6, 2024

Thanks for the hint. I will see if I can come up with some good tests over the weekend.

@jvllmr
Copy link
Author

jvllmr commented Sep 6, 2024

I updated the PR with tests for all the new logic I introduced, but I don't know why 99.0% coverage are still shown here.
It was green at first but then went back to red. When looking at the detailed report it still says 100%.
I'm also sorry for the messed up commit history (squash to the rescue).

Anyway, I added more FastAPI features to my benchmark and the improvement became even more significant:
https://jvllmr.github.io/fastapi-deferred-init/dev/bench/

@jvllmr
Copy link
Author

jvllmr commented Sep 6, 2024

I actually found the offending lines. For some reason the summary at the bottom showed 100%, but I found the lines immediately when checking "Hide covered". All green now ✅ 🏁

remove useless checks in test

test defer_init flag on route

add route to test app

fix coverage again
@jvllmr
Copy link
Author

jvllmr commented Sep 7, 2024

I dropped the unintentional commits just to be sure

@svlandeg
Copy link
Member

svlandeg commented Sep 9, 2024

Thanks! We've got a bit of a reviewing queue at the moment, but we've added this one and will get back to you once we've been able to review it in more detail 🙏

@github-actions github-actions bot removed the conflicts Automatically generated when a PR has a merge conflict label Nov 3, 2025
@github-actions github-actions bot added the conflicts Automatically generated when a PR has a merge conflict label Dec 17, 2025
@github-actions
Copy link
Contributor

This pull request has a merge conflict that needs to be resolved.

@github-actions github-actions bot removed the conflicts Automatically generated when a PR has a merge conflict label Dec 18, 2025
Signed-off-by: Jan Vollmer <[email protected]>
Signed-off-by: Jan Vollmer <[email protected]>
Signed-off-by: Jan Vollmer <[email protected]>
@codspeed-hq
Copy link

codspeed-hq bot commented Dec 18, 2025

Merging this PR will not alter performance

✅ 20 untouched benchmarks


Comparing jvllmr:deferred-init (c539578) with master (b93c964)1

Open in CodSpeed

Footnotes

  1. No successful run was found on master (ed12105) during the generation of this report, so b93c964 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@github-actions
Copy link
Contributor

This pull request has a merge conflict that needs to be resolved.

@github-actions github-actions bot added the conflicts Automatically generated when a PR has a merge conflict label Dec 21, 2025
@github-actions github-actions bot removed the conflicts Automatically generated when a PR has a merge conflict label Dec 22, 2025
@github-actions github-actions bot added the conflicts Automatically generated when a PR has a merge conflict label Feb 6, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

This pull request has a merge conflict that needs to be resolved.

@github-actions github-actions bot removed the conflicts Automatically generated when a PR has a merge conflict label Feb 6, 2026
Signed-off-by: Jan Vollmer <[email protected]>
@github-actions github-actions bot added the conflicts Automatically generated when a PR has a merge conflict label Feb 7, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Feb 7, 2026

This pull request has a merge conflict that needs to be resolved.

@github-actions github-actions bot added conflicts Automatically generated when a PR has a merge conflict and removed conflicts Automatically generated when a PR has a merge conflict labels Feb 7, 2026
@github-actions
Copy link
Contributor

This pull request has a merge conflict that needs to be resolved.

@github-actions github-actions bot removed the conflicts Automatically generated when a PR has a merge conflict label Feb 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants