PostgreSQL Common Table Expressions vs a temporary table?
There are a few subtle differences, but nothing drastic:


You can add indexes on a temp table;
Temp tables exist for the life of the session (or, if ON COMMIT DROP, transaction), wheras WITH is always scoped strictly to the query;
If a query invokes a function/procedure, it can see the temp table, but it can not see any WITH table-expressions;
A temp table generates VACUUM work on the system catalogs that WITH doesn't, it needs an extra round trip to create/fill it, and it requires extra work in the server's cache management, so it's slightly less efficient.


Overall, you should prefer WITH to temp tables unless you know you will benefit from creating an index.

However, the other option, a subquery in the FROM clause, has a very different set of advantages. It can be inlined, in particular, and qualifiers can be pulled up / pushed down. I wrote about this in a recent blog article.