The advantages of Erlang are not limited to distribution, but also excellent concurrency. By this, I don't necessarily mean high throughput and amount of queries served per second, but a general resilience over high loads.

Because every task can be broken into bits running concurrently (note: not necessarily in parallel, just concurrently) and because the Erlang VM has full control of the runtime, there is a general good load balancing where the applications remain responsive (although slower) over high load, rather than just dropping calls.

Another part comes from the high reliability. Of course a broken app is annoying. Fortunately, there are a lot of technologies with stuff like load balancers and whatnot that make it easy to scale in any language and deploy new releases without downtime no matter the kind of code you use. By doing this, the burden of high reliability and scalability is often moved to the database layer. An Erlang web app won't shine that much from this perspective -- the DB might do the heavy lifting.

However, the way exceptions are handled with Erlang and its supervision trees changes the way you write programs. You only program for the cases you know how to handle. For the others, you "let it crash." This is a bit weird at first, but what this really means is "only fix the errors you know how to fix" -- the runtime is made to support living with the other kind of errors.

The other aspect of using concurrent actors to do error management is that it shifts the perspective of where exceptions are to be handled. In most languages, exceptions are managed from within the execution flow of the program:

main
(top level try catch)
|
some code
(might catch errors)
|
deeper calls with
own error management

The problem with this is that your regular code needs to handle outstanding errors on every level or you just delegate the burden of making things safe to the layer above until you end up having the eternal top-level try catch (it's more complex than that obviously). Erlang supports this model too. However, it also supports supervision trees, which change the structure in the following way:

some actor ------------------- supervisor
| > supervisor
some code <--> other actor -- supervisor
| |
deeper calls more calls

(I hope the drawings are clear)

Here what I mean to illustrate is that actors who run code are being supervised by other concurrent 'supervisor' actors who are dedicated to handling errors that won't be handled by 'worker' actors. They can restart dead workers, notify the user or a logging system of a problem, propagate the killing of workers to dependent ones, etc.

This means the burden of error handling is shifted from within your standard and correct execution path to a concept litterally parallel to it. This lets you organize your code towards non-defensive programming while keeping it more stable at the same time.

This is not to say standard exceptions are not the way. They're still pretty useful. However, there is more than one class of error that can happen in software, and I think Erlang deals with this beautifully.

In my opinion, this concept of supervision trees is what Erlang really is about. People come in for the concurrency, but they stay for the supervision trees.