The first is don't be afraid of them. They are extremely powerful and you can do a lot with them. They can also go a long ways towards making code a lot more readable.
the second though is that they are optimization fences. Consequently you really want to do as much filtering in a CTE as you can. having a CTE that returns a very large result set is probably not a good idea. The smaller the amount of data returned the better.
This is particularly important with recursive CTE's because you are doing one additional scan per level of recursion, and it is having to go back and populate the returned set after each one. If you are generating a tree with millions of nodes you better have a heck of a lot of RAM and appropriate tuning done in advance. It's much better though if you can just render the portion of the tree you are interested in.