Rails engines are a way to create rails apps that contain plug-and-play code from either a gem or even a local codebase. Rails engine helps to abstract out the common functionality of a rails app into a gem that can be used for multiple projects if required. A common example of a rails engine gem would be the Solidus e-commerce platform. Solidus plugs into an existing Rails app as an engine and extends the functionality of the Rails app by providing e-commerce stores and admin pages. It adds more controllers, routes, and models (which are all native to a rails app), and these engines could be configured or extended easily.
There's a common misconception that engines are only useful as open-source gems. But this is not true. In our experience, we have seen private source codes that have had extensive use of rails engines which are private gems. This is a way to have private gems within one's organization. There are even instances where the rails engine gem was used only in a single project, but still, it made sense to abstract out the engine for code maintenance advantages.
The best part of rails engines are the following:
Microservices help organizations to develop codebases that are separated from each other but living in the same rails app. This helps to create separate test cases, CI/CD pipelines, and code management and also helps in project management. Organizations can create different engines out of their regular codebase which can help them to maintain the codebases separately.
Some of the advantages of the abstracted codebases:
Microservices can help in creating abstracted codebases with all the advantages mentioned above. That said, microservices also have overheads that are complicated which adds more delays in feature development. Microservices are suitable for bigger teams and organizations that can manage the complexity that arises out of the maintaining the multitude of problems that involve starting from deployments to debugging. Rails provides a mid-way solution that is not microservices or monoliths. This solution is rails engines.
Rails engines can create different codebases that are maintained by different teams and can be published as gems which are then pulled into Rails apps using version management. This ensures that code is not cluttered in a monolith and separated by concerns. Testability becomes an important aspect where rails engines can contain their separate test cases. So when publishing the rails engine as a gem, tests, and CI can identify any regressions.
Rails engines also help to create extendable modules which means that the same engine can be reused in different projects. For example, let's say an organization creates an internal rails engine for authentication. That same rails engine can be used in multiple different rails projects sharing the same code and also the same UI with branding. And if there are changes in the any logic, the rails engine can be published as another version which can be pulled by other rails apps.