GUI is static, with a limited set of widgets, generated from the XML descriptor file
the module does not have access to the full scene (only to the selected input nodes)
only runs when the user clicks apply (or an input node is changed and auto-update is enabled)
always performs all computations from scratch
However, these limitations allow faster, simpler development and asynchronous execution (application GUI is not blocked).
CLI modules can be also created from any existing command-line applications or Python scripts - by simply creating an XML file that describes command-line arguments.
The original motivation for CLI modules (which is still valid) was to allow people to write or adapt traditional C or C++ programs so that they would have a GUI. So they only rely on having a main(argc,argv) entry point with data access via files and progress reporting to stdout and errors reported via stderr and return codes. A lot of algorithms, like in ITK, are not interactive anyway and by writing them as CLI modules you can reuse the executable in batch jobs or other environments without having Slicer as a dependency.