The advantages of microframeworks (e.g. Sinatra, Flask, Javelin, etc) are that as your needs expand, you can bolt-on the additional functionality as you see fit, from a "best of breed" selection of your favorite libraries.
The advantages of batteries-included frameworks (e.g. Rails, Django, Spring, etc) are that your application is easier to find people to work on, and has a greater change of remaining coherent and maintainable for longer.
In the real world with microframeworks, some rock star starts a greenfield project, and has a delightful fun time selecting their personal picks of various community libraries to bolt functionality on top of the microframework. Then that original developer moves on 6 months later. The best-case scenario is that half of their pet community libraries are no longer being maintained 12 months after that, and the team has to constantly sink time into migrating pieces of the app to other actively maintained libraries. The worst-case scenerio is that you get the next-generation rock star, who wastes time ripping out pieces for no real reason other than using their own personal pet favorites.
In my experience, the microframeworks are ideal for apps where you can be fairly confident that the scope will never expand (e.g. simple Lambda functions). Otherwise, they're popular toys for startups, and nooks and crannies of large enterprises where no one's really providing any oversight over the juniors.
Does it also have the advantage of not having to remember to import things? Like, does Spring prevent CSRF attacks etc. out of the box, and it's very difficult to accidentally create a vulnerability using it?
Lots of devs need the prebaked structure. It is honestly helpful in many cases, but can also be a frustrating maze at times to find the hook/extension point you need.
- an underlying service to listen for http/https requests (eg: "web server")
- easily map inputs to code/services ("routing"); often also providing helper functionality to extract data from paths, map and convert JSON (etc) to domain objects
- some way to inject your data into a return "view" (json, html, xml, ???). Might also include reusable view code snippets (eg: "partials"), and/or some "design pattern" (eg: "layouts") system
- an ORM or other db-layer abstraction
- some background job processing abstraction
That's about all you need; the extent to which the framework simplifies doing those things is akin to the amount of constraints. Everything else is gravy.
Do note that "big" frameworks that provide ALL of that plus more can often be harder to work with since you might be forced to learn more than you need, and it's overwhelming.
There's also the concern of modularity... if I don't like their ORM, can I use my own? How hard is it to add functionality not provided, etc.
And my PR's were routinely flagged for writing 3-5 lines of idiomatic python that any python programmer (indeed, any PROGRAMMER) would have understood instead of spending half a day to try and find the "Django way" (or worse, the "whatever 5000 line plugin we installed to save the programmer from having to repeat 2 lines of idiomatic python 10-12 times") way to do it.
Their (IMO insane) adherence to the common, but misunderstood idea of DRY was insanely unproductive.
These frameworks become "languages" in themselves, and unless you're in it all day every day, it's _harder_ to get things done due to their incredibly large attack surface.
I'm very curious to see how that may look like. I've been using Django for years now and was never faced with such choice.
By definition, almost, compared to the bunch of libraries approach, whch is more flexible and composable.