diff --git a/core/commands/refs.go b/core/commands/refs.go
index 0cfc9bc31f4a1f3022971956513d8c36a4f29b8b..1d6d5a056e68e9b962e25df76a5126c92612af5e 100644
--- a/core/commands/refs.go
+++ b/core/commands/refs.go
@@ -2,10 +2,11 @@ package commands
 
 import (
 	"bytes"
-	"fmt"
 	"io"
+	"sync"
+
+	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
 
-	mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
 	cmds "github.com/jbenet/go-ipfs/commands"
 	"github.com/jbenet/go-ipfs/core"
 	dag "github.com/jbenet/go-ipfs/merkledag"
@@ -44,6 +45,7 @@ Note: list all refs recursively with -r.
 		cmds.StringArg("ipfs-path", true, true, "Path to the object(s) to list refs from"),
 	},
 	Options: []cmds.Option{
+		cmds.BoolOption("edges", "e", "Emit edge format: <from> -> <to>"),
 		cmds.BoolOption("unique", "u", "Omit duplicate refs from output"),
 		cmds.BoolOption("recursive", "r", "Recursively list links of child nodes"),
 	},
@@ -53,84 +55,191 @@ Note: list all refs recursively with -r.
 			return nil, err
 		}
 
-		unique, found, err := req.Option("unique").Bool()
+		unique, _, err := req.Option("unique").Bool()
 		if err != nil {
 			return nil, err
 		}
-		if !found {
-			unique = false
+
+		recursive, _, err := req.Option("recursive").Bool()
+		if err != nil {
+			return nil, err
 		}
 
-		recursive, found, err := req.Option("recursive").Bool()
+		edges, _, err := req.Option("edges").Bool()
 		if err != nil {
 			return nil, err
 		}
-		if !found {
-			recursive = false
+
+		objs, err := objectsForPaths(n, req.Arguments())
+		if err != nil {
+			return nil, err
 		}
 
-		return getRefs(n, req.Arguments(), unique, recursive)
-	},
-	Type: KeyList{},
-	Marshalers: cmds.MarshalerMap{
-		cmds.Text: KeyListTextMarshaler,
+		piper, pipew := io.Pipe()
+		eptr := &ErrPassThroughReader{R: piper}
+
+		go func() {
+			defer pipew.Close()
+
+			rw := RefWriter{
+				W:         pipew,
+				DAG:       n.DAG,
+				Ctx:       n.Context(),
+				Unique:    unique,
+				PrintEdge: edges,
+				Recursive: recursive,
+			}
+
+			for _, o := range objs {
+				if _, err := rw.WriteRefs(o); err != nil {
+					eptr.SetError(err)
+				}
+			}
+		}()
+
+		return eptr, nil
 	},
 }
 
-func getRefs(n *core.IpfsNode, paths []string, unique, recursive bool) (*KeyList, error) {
-	var refsSeen map[u.Key]bool
-	if unique {
-		refsSeen = make(map[u.Key]bool)
+func objectsForPaths(n *core.IpfsNode, paths []string) ([]*dag.Node, error) {
+	objects := make([]*dag.Node, len(paths))
+	for i, p := range paths {
+		o, err := n.Resolver.ResolvePath(p)
+		if err != nil {
+			return nil, err
+		}
+		objects[i] = o
+	}
+	return objects, nil
+}
+
+// ErrPassThroughReader is a reader that may return an externally set error.
+type ErrPassThroughReader struct {
+	R   io.ReadCloser
+	err error
+
+	sync.RWMutex
+}
+
+func (r *ErrPassThroughReader) Error() error {
+	r.RLock()
+	defer r.RUnlock()
+	return r.err
+}
+
+func (r *ErrPassThroughReader) SetError(err error) {
+	r.Lock()
+	r.err = err
+	r.Unlock()
+}
+
+func (r *ErrPassThroughReader) Read(buf []byte) (int, error) {
+	err := r.Error()
+	if err != nil {
+		return 0, err
+	}
+
+	return r.R.Read(buf)
+}
+
+func (r *ErrPassThroughReader) Close() error {
+	err1 := r.R.Close()
+	err2 := r.Error()
+	if err2 != nil {
+		return err2
 	}
+	return err1
+}
+
+type RefWriter struct {
+	W   io.Writer
+	DAG dag.DAGService
+	Ctx context.Context
 
-	refs := make([]u.Key, 0)
+	Unique    bool
+	Recursive bool
+	PrintEdge bool
+
+	seen map[u.Key]struct{}
+}
+
+// WriteRefs writes refs of the given object to the underlying writer.
+func (rw *RefWriter) WriteRefs(n *dag.Node) (int, error) {
+	nkey, err := n.Key()
+	if err != nil {
+		return 0, err
+	}
+
+	if rw.skip(nkey) {
+		return 0, nil
+	}
+
+	count := 0
+	for _, l := range n.Links {
+		lk := u.Key(l.Hash)
+
+		if rw.skip(lk) {
+			continue
+		}
+
+		if err := rw.WriteEdge(nkey, lk); err != nil {
+			return count, err
+		}
+		count++
 
-	for _, path := range paths {
-		object, err := n.Resolver.ResolvePath(path)
+		if !rw.Recursive {
+			continue
+		}
+
+		child, err := l.GetNode(rw.DAG)
 		if err != nil {
-			return nil, err
+			return count, err
 		}
 
-		refs, err = addRefs(n, object, refs, refsSeen, recursive)
+		c, err := rw.WriteRefs(child)
+		count += c
 		if err != nil {
-			return nil, err
+			return count, err
 		}
 	}
-
-	return &KeyList{refs}, nil
+	return count, nil
 }
 
-func addRefs(n *core.IpfsNode, object *dag.Node, refs []u.Key, refsSeen map[u.Key]bool, recursive bool) ([]u.Key, error) {
-	for _, link := range object.Links {
-		var found bool
-		found, refs = addRef(link.Hash, refs, refsSeen)
-
-		if recursive && !found {
-			child, err := n.DAG.Get(u.Key(link.Hash))
-			if err != nil {
-				return nil, fmt.Errorf("cannot retrieve %s (%s)", link.Hash.B58String(), err)
-			}
+// skip returns whether to skip a key
+func (rw *RefWriter) skip(k u.Key) bool {
+	if !rw.Unique {
+		return false
+	}
 
-			refs, err = addRefs(n, child, refs, refsSeen, recursive)
-			if err != nil {
-				return nil, err
-			}
-		}
+	if rw.seen == nil {
+		rw.seen = make(map[u.Key]struct{})
 	}
 
-	return refs, nil
+	_, found := rw.seen[k]
+	if !found {
+		rw.seen[k] = struct{}{}
+	}
+	return found
 }
 
-func addRef(h mh.Multihash, refs []u.Key, refsSeen map[u.Key]bool) (bool, []u.Key) {
-	key := u.Key(h)
-	if refsSeen != nil {
-		_, found := refsSeen[key]
-		if found {
-			return true, refs
+// Write one edge
+func (rw *RefWriter) WriteEdge(from, to u.Key) error {
+	if rw.Ctx != nil {
+		select {
+		case <-rw.Ctx.Done(): // just in case.
+			return rw.Ctx.Err()
+		default:
 		}
-		refsSeen[key] = true
 	}
 
-	refs = append(refs, key)
-	return false, refs
+	var s string
+	if rw.PrintEdge {
+		s = from.Pretty() + " -> "
+	}
+	s += to.Pretty() + "\n"
+
+	if _, err := rw.W.Write([]byte(s)); err != nil {
+		return err
+	}
+	return nil
 }