diff --git a/pgio/doc.go b/pgio/doc.go
new file mode 100644
index 00000000..36233a47
--- /dev/null
+++ b/pgio/doc.go
@@ -0,0 +1,8 @@
+// Package pgio a extremely low-level IO toolkit for the PostgreSQL wire protocol.
+/*
+pgio provides functions for reading and writing integers from io.Reader and
+io.Writer while doing byte order conversion. It publishes interfaces which
+readers and writers may implement to decode and encode messages with the minimum
+of memory allocations.
+*/
+package pgio
diff --git a/pgtype/typed_reader.go b/pgio/read.go
similarity index 91%
rename from pgtype/typed_reader.go
rename to pgio/read.go
index 29997338..7c39162c 100644
--- a/pgtype/typed_reader.go
+++ b/pgio/read.go
@@ -1,19 +1,19 @@
-package pgtype
+package pgio
 
 import (
 	"encoding/binary"
 	"io"
 )
 
-type uint16Reader interface {
+type Uint16Reader interface {
 	ReadUint16() (n uint16, err error)
 }
 
-type uint32Reader interface {
+type Uint32Reader interface {
 	ReadUint32() (n uint32, err error)
 }
 
-type uint64Reader interface {
+type Uint64Reader interface {
 	ReadUint64() (n uint64, err error)
 }
 
@@ -32,7 +32,7 @@ func ReadByte(r io.Reader) (byte, error) {
 // may be more efficient than directly using Read if r provides a ReadUint16
 // method.
 func ReadUint16(r io.Reader) (uint16, error) {
-	if r, ok := r.(uint16Reader); ok {
+	if r, ok := r.(Uint16Reader); ok {
 		return r.ReadUint16()
 	}
 
@@ -57,7 +57,7 @@ func ReadInt16(r io.Reader) (int16, error) {
 // may be more efficient than directly using Read if r provides a ReadUint32
 // method.
 func ReadUint32(r io.Reader) (uint32, error) {
-	if r, ok := r.(uint32Reader); ok {
+	if r, ok := r.(Uint32Reader); ok {
 		return r.ReadUint32()
 	}
 
@@ -82,7 +82,7 @@ func ReadInt32(r io.Reader) (int32, error) {
 // may be more efficient than directly using Read if r provides a ReadUint64
 // method.
 func ReadUint64(r io.Reader) (uint64, error) {
-	if r, ok := r.(uint64Reader); ok {
+	if r, ok := r.(Uint64Reader); ok {
 		return r.ReadUint64()
 	}
 
diff --git a/pgtype/typed_writer.go b/pgio/write.go
similarity index 91%
rename from pgtype/typed_writer.go
rename to pgio/write.go
index 3f175343..823fbd00 100644
--- a/pgtype/typed_writer.go
+++ b/pgio/write.go
@@ -1,19 +1,19 @@
-package pgtype
+package pgio
 
 import (
 	"encoding/binary"
 	"io"
 )
 
-type uint16Writer interface {
+type Uint16Writer interface {
 	WriteUint16(uint16) (n int, err error)
 }
 
-type uint32Writer interface {
+type Uint32Writer interface {
 	WriteUint32(uint32) (n int, err error)
 }
 
-type uint64Writer interface {
+type Uint64Writer interface {
 	WriteUint64(uint64) (n int, err error)
 }
 
@@ -30,7 +30,7 @@ func WriteByte(w io.Writer, b byte) error {
 // may be more efficient than directly using Write if w provides a WriteUint16
 // method.
 func WriteUint16(w io.Writer, n uint16) (int, error) {
-	if w, ok := w.(uint16Writer); ok {
+	if w, ok := w.(Uint16Writer); ok {
 		return w.WriteUint16(n)
 	}
 	b := make([]byte, 2)
@@ -49,7 +49,7 @@ func WriteInt16(w io.Writer, n int16) (int, error) {
 // may be more efficient than directly using Write if w provides a WriteUint32
 // method.
 func WriteUint32(w io.Writer, n uint32) (int, error) {
-	if w, ok := w.(uint32Writer); ok {
+	if w, ok := w.(Uint32Writer); ok {
 		return w.WriteUint32(n)
 	}
 	b := make([]byte, 4)
@@ -68,7 +68,7 @@ func WriteInt32(w io.Writer, n int32) (int, error) {
 // may be more efficient than directly using Write if w provides a WriteUint64
 // method.
 func WriteUint64(w io.Writer, n uint64) (int, error) {
-	if w, ok := w.(uint64Writer); ok {
+	if w, ok := w.(Uint64Writer); ok {
 		return w.WriteUint64(n)
 	}
 	b := make([]byte, 8)
diff --git a/pgtype/int4.go b/pgtype/int4.go
index 29b5dd1b..167b1eda 100644
--- a/pgtype/int4.go
+++ b/pgtype/int4.go
@@ -4,12 +4,14 @@ import (
 	"fmt"
 	"io"
 	"strconv"
+
+	"github.com/jackc/pgx/pgio"
 )
 
 type Int4 int32
 
 func (i *Int4) DecodeText(r io.Reader) error {
-	size, err := ReadInt32(r)
+	size, err := pgio.ReadInt32(r)
 	if err != nil {
 		return err
 	}
@@ -34,7 +36,7 @@ func (i *Int4) DecodeText(r io.Reader) error {
 }
 
 func (i *Int4) DecodeBinary(r io.Reader) error {
-	size, err := ReadInt32(r)
+	size, err := pgio.ReadInt32(r)
 	if err != nil {
 		return err
 	}
@@ -43,7 +45,7 @@ func (i *Int4) DecodeBinary(r io.Reader) error {
 		return fmt.Errorf("invalid length for int4: %v", size)
 	}
 
-	n, err := ReadInt32(r)
+	n, err := pgio.ReadInt32(r)
 	if err != nil {
 		return err
 	}
@@ -54,7 +56,7 @@ func (i *Int4) DecodeBinary(r io.Reader) error {
 
 func (i Int4) EncodeText(w io.Writer) error {
 	s := strconv.FormatInt(int64(i), 10)
-	_, err := WriteInt32(w, int32(len(s)))
+	_, err := pgio.WriteInt32(w, int32(len(s)))
 	if err != nil {
 		return nil
 	}
@@ -63,11 +65,11 @@ func (i Int4) EncodeText(w io.Writer) error {
 }
 
 func (i Int4) EncodeBinary(w io.Writer) error {
-	_, err := WriteInt32(w, 4)
+	_, err := pgio.WriteInt32(w, 4)
 	if err != nil {
 		return err
 	}
 
-	_, err = WriteInt32(w, int32(i))
+	_, err = pgio.WriteInt32(w, int32(i))
 	return err
 }