diff --git a/builder.go b/builder.go
new file mode 100644
index 0000000..af33aac
--- /dev/null
+++ b/builder.go
@@ -0,0 +1,74 @@
+package cid
+
+import (
+	mh "github.com/multiformats/go-multihash"
+)
+
+type Builder interface {
+	Sum(data []byte) (*Cid, error)
+	GetCodec() uint64
+	WithCodec(uint64) Builder
+}
+
+type V0Builder struct{}
+
+type V1Builder struct {
+	Codec    uint64
+	MhType   uint64
+	MhLength int // MhLength <= 0 means the default length
+}
+
+func (p Prefix) GetCodec() uint64 {
+	return p.Codec
+}
+
+func (p Prefix) WithCodec(c uint64) Builder {
+	if c == p.Codec {
+		return p
+	}
+	p.Codec = c
+	if c != DagProtobuf {
+		p.Version = 1
+	}
+	return p
+}
+
+func (p V0Builder) Sum(data []byte) (*Cid, error) {
+	hash, err := mh.Sum(data, mh.SHA2_256, -1)
+	if err != nil {
+		return nil, err
+	}
+	return NewCidV0(hash), nil
+}
+
+func (p V0Builder) GetCodec() uint64 {
+	return DagProtobuf
+}
+
+func (p V0Builder) WithCodec(c uint64) Builder {
+	if c == DagProtobuf {
+		return p
+	}
+	return V1Builder{Codec: c, MhType: mh.SHA2_256}
+}
+
+func (p V1Builder) Sum(data []byte) (*Cid, error) {
+	mhLen := p.MhLength
+	if mhLen <= 0 {
+		mhLen = -1
+	}
+	hash, err := mh.Sum(data, p.MhType, mhLen)
+	if err != nil {
+		return nil, err
+	}
+	return NewCidV1(p.Codec, hash), nil
+}
+
+func (p V1Builder) GetCodec() uint64 {
+	return p.Codec
+}
+
+func (p V1Builder) WithCodec(c uint64) Builder {
+	p.Codec = c
+	return p
+}
diff --git a/builder_test.go b/builder_test.go
new file mode 100644
index 0000000..dc6f35c
--- /dev/null
+++ b/builder_test.go
@@ -0,0 +1,92 @@
+package cid
+
+import (
+	"testing"
+
+	mh "github.com/multiformats/go-multihash"
+)
+
+func TestV0Builder(t *testing.T) {
+	data := []byte("this is some test content")
+
+	// Construct c1
+	format := V0Builder{}
+	c1, err := format.Sum(data)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Construct c2
+	hash, err := mh.Sum(data, mh.SHA2_256, -1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	c2 := NewCidV0(hash)
+
+	if !c1.Equals(c2) {
+		t.Fatal("cids mismatch")
+	}
+	if c1.Prefix() != c2.Prefix() {
+		t.Fatal("prefixes mismatch")
+	}
+}
+
+func TestV1Builder(t *testing.T) {
+	data := []byte("this is some test content")
+
+	// Construct c1
+	format := V1Builder{Codec: DagCBOR, MhType: mh.SHA2_256}
+	c1, err := format.Sum(data)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Construct c2
+	hash, err := mh.Sum(data, mh.SHA2_256, -1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	c2 := NewCidV1(DagCBOR, hash)
+
+	if !c1.Equals(c2) {
+		t.Fatal("cids mismatch")
+	}
+	if c1.Prefix() != c2.Prefix() {
+		t.Fatal("prefixes mismatch")
+	}
+}
+
+func TestCodecChange(t *testing.T) {
+	t.Run("Prefix-CidV0", func(t *testing.T) {
+		p := Prefix{Version: 0, Codec: DagProtobuf, MhType: mh.SHA2_256, MhLength: mh.DefaultLengths[mh.SHA2_256]}
+		testCodecChange(t, p)
+	})
+	t.Run("Prefix-CidV1", func(t *testing.T) {
+		p := Prefix{Version: 1, Codec: DagProtobuf, MhType: mh.SHA2_256, MhLength: mh.DefaultLengths[mh.SHA2_256]}
+		testCodecChange(t, p)
+	})
+	t.Run("V0Builder", func(t *testing.T) {
+		testCodecChange(t, V0Builder{})
+	})
+	t.Run("V1Builder", func(t *testing.T) {
+		testCodecChange(t, V1Builder{Codec: DagProtobuf, MhType: mh.SHA2_256})
+	})
+}
+
+func testCodecChange(t *testing.T, b Builder) {
+	data := []byte("this is some test content")
+
+	if b.GetCodec() != DagProtobuf {
+		t.Fatal("original builder not using Protobuf codec")
+	}
+
+	b = b.WithCodec(Raw)
+	c, err := b.Sum(data)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if c.Type() != Raw {
+		t.Fatal("new cid codec did not change to Raw")
+	}
+}
diff --git a/cid.go b/cid.go
index 99a26a6..4c91344 100644
--- a/cid.go
+++ b/cid.go
@@ -144,27 +144,6 @@ func NewCidV1(codecType uint64, mhash mh.Multihash) *Cid {
 	}
 }
 
-// NewPrefixV0 returns a CIDv0 prefix with the specified multihash type.
-func NewPrefixV0(mhType uint64) Prefix {
-	return Prefix{
-		MhType:   mhType,
-		MhLength: mh.DefaultLengths[mhType],
-		Version:  0,
-		Codec:    DagProtobuf,
-	}
-}
-
-// NewPrefixV1 returns a CIDv1 prefix with the specified codec and multihash
-// type.
-func NewPrefixV1(codecType uint64, mhType uint64) Prefix {
-	return Prefix{
-		MhType:   mhType,
-		MhLength: mh.DefaultLengths[mhType],
-		Version:  1,
-		Codec:    codecType,
-	}
-}
-
 // Cid represents a self-describing content adressed
 // identifier. It is formed by a Version, a Codec (which indicates
 // a multicodec-packed content type) and a Multihash.
@@ -442,6 +421,8 @@ func (c *Cid) Prefix() Prefix {
 // that is, the Version, the Codec, the Multihash type
 // and the Multihash length. It does not contains
 // any actual content information.
+// NOTE: The use -1 in MhLength to mean default length is deprecated,
+//   use the V0Builder or V1Builder structures instead
 type Prefix struct {
 	Version  uint64
 	Codec    uint64
diff --git a/deprecated.go b/deprecated.go
new file mode 100644
index 0000000..cd889f9
--- /dev/null
+++ b/deprecated.go
@@ -0,0 +1,28 @@
+package cid
+
+import (
+	mh "github.com/multiformats/go-multihash"
+)
+
+// NewPrefixV0 returns a CIDv0 prefix with the specified multihash type.
+// DEPRECATED: Use V0Builder
+func NewPrefixV0(mhType uint64) Prefix {
+	return Prefix{
+		MhType:   mhType,
+		MhLength: mh.DefaultLengths[mhType],
+		Version:  0,
+		Codec:    DagProtobuf,
+	}
+}
+
+// NewPrefixV1 returns a CIDv1 prefix with the specified codec and multihash
+// type.
+// DEPRECATED: Use V1Builder
+func NewPrefixV1(codecType uint64, mhType uint64) Prefix {
+	return Prefix{
+		MhType:   mhType,
+		MhLength: mh.DefaultLengths[mhType],
+		Version:  1,
+		Codec:    codecType,
+	}
+}