diff --git a/contrib/codecs/rdwr/codec.go b/contrib/codecs/rdwr/codec.go
index 9235b1252d899e744357c3813880d3d5b594bcf0..e75a245a11c5e9ae497b852f1e94330187b535b8 100644
--- a/contrib/codecs/rdwr/codec.go
+++ b/contrib/codecs/rdwr/codec.go
@@ -3,11 +3,11 @@ package rdwr
 import (
 	"bufio"
 	"context"
+	"encoding/json"
 	"io"
 	"sync"
 
-	"github.com/goccy/go-json"
-
+	"gfx.cafe/open/jrpc/pkg/jjson"
 	"gfx.cafe/open/jrpc/pkg/jsonrpc"
 	"gfx.cafe/open/jrpc/pkg/serverutil"
 )
@@ -19,8 +19,6 @@ type Codec struct {
 	rd io.Reader
 	wr *bufio.Writer
 
-	dec     *json.Decoder
-	decBuf  json.RawMessage
 	decLock sync.Mutex
 }
 
@@ -31,7 +29,6 @@ func NewCodec(rd io.Reader, wr io.Writer) *Codec {
 		cn:  cn,
 		rd:  bufio.NewReader(rd),
 		wr:  bufio.NewWriter(wr),
-		dec: json.NewDecoder(rd),
 	}
 	return c
 }
@@ -48,13 +45,12 @@ func (c *Codec) PeerInfo() jsonrpc.PeerInfo {
 func (c *Codec) decodeSingleMessage(ctx context.Context) (*serverutil.Bundle, error) {
 	c.decLock.Lock()
 	defer c.decLock.Unlock()
-	//c.decBuf = c.decBuf[:0]
-	c.decBuf = json.RawMessage{}
-	err := c.dec.DecodeContext(ctx, &c.decBuf)
+	decBuf := make(json.RawMessage, 0)
+	err := jjson.Decode(c.rd, &decBuf)
 	if err != nil {
 		return nil, err
 	}
-	return serverutil.ParseBundle(c.decBuf), nil
+	return serverutil.ParseBundle(decBuf), nil
 }
 
 func (c *Codec) ReadBatch(ctx context.Context) ([]*jsonrpc.Message, bool, error) {
diff --git a/contrib/codecs/websocket/codec.go b/contrib/codecs/websocket/codec.go
index 35fc49472f8a22fd4a9692ba49d6da67e457afe2..3ad099fe5be580fc7832bcd11bec678aef4f51cc 100644
--- a/contrib/codecs/websocket/codec.go
+++ b/contrib/codecs/websocket/codec.go
@@ -2,16 +2,17 @@ package websocket
 
 import (
 	"context"
+	"encoding/json"
 	"io"
 	"net/http"
 	"sync"
 	"time"
 
 	"gfx.cafe/open/websocket"
-	"github.com/goccy/go-json"
 
 	_ "net/http/pprof"
 
+	"gfx.cafe/open/jrpc/pkg/jjson"
 	"gfx.cafe/open/jrpc/pkg/jsonrpc"
 	"gfx.cafe/open/jrpc/pkg/serverutil"
 )
@@ -81,7 +82,7 @@ func (c *Codec) decodeSingleMessage(ctx context.Context) (*serverutil.Bundle, er
 		return nil, err
 	}
 	defer io.Copy(io.Discard, r)
-	err = json.NewDecoder(r).DecodeContext(ctx, &c.decBuf)
+	err = jjson.Decode(r, &c.decBuf)
 	if err != nil {
 		return nil, err
 	}
diff --git a/contrib/extension/subscription/subscription.go b/contrib/extension/subscription/subscription.go
index 91d53d9c77937412e2368de0599638eb52b3d40e..61b1f346e3a91d019751311b451903894fa2f2ed 100644
--- a/contrib/extension/subscription/subscription.go
+++ b/contrib/extension/subscription/subscription.go
@@ -4,15 +4,15 @@ import (
 	"context"
 	"encoding/binary"
 	"encoding/hex"
+	"encoding/json"
 	"errors"
 	"strings"
 	"sync"
 	"sync/atomic"
 
+	"gfx.cafe/open/jrpc/pkg/jjson"
 	"gfx.cafe/open/jrpc/pkg/jsonrpc"
 	"gfx.cafe/util/go/frand"
-
-	json "github.com/goccy/go-json"
 )
 
 var serviceMethodSeparator = "/"
@@ -95,7 +95,7 @@ type Notifier struct {
 // Notify sends a notification to the client with the given data as payload.
 // If an error occurs the RPC connection is closed and the error is returned.
 func (n *Notifier) Notify(data any) error {
-	enc, err := json.Marshal(data)
+	enc, err := jjson.Marshal(data)
 	if err != nil {
 		return err
 	}
@@ -109,7 +109,7 @@ func (n *Notifier) Err() <-chan error {
 }
 
 func (n *Notifier) send(data json.RawMessage) error {
-	params, _ := json.Marshal(&subscriptionResult{ID: string(n.id), Result: data})
+	params, _ := jjson.Marshal(&subscriptionResult{ID: string(n.id), Result: data})
 	return n.h.Notify(
 		n.namespace+
 			serviceMethodSeparator+
diff --git a/contrib/handlers/argreflect/json.go b/contrib/handlers/argreflect/json.go
index b66015518138268615cb0c3a0e5fa2b049291f70..31572361cef8cc2faf3a855268bc471876cf7de8 100644
--- a/contrib/handlers/argreflect/json.go
+++ b/contrib/handlers/argreflect/json.go
@@ -1,12 +1,13 @@
 package argreflect
 
 import (
+	"encoding/json"
 	"fmt"
 	"reflect"
 
+	"gfx.cafe/open/jrpc/pkg/jjson"
 	"gfx.cafe/open/jrpc/pkg/jsonrpc"
 	"github.com/go-faster/jx"
-	"github.com/goccy/go-json"
 )
 
 // parsePositionalArguments tries to parse the given args to an array of values with the
@@ -59,7 +60,7 @@ func parseArgumentArray(p json.RawMessage, types []reflect.Type) ([]reflect.Valu
 		if err != nil {
 			return args, jsonrpc.NewInvalidParamsError(fmt.Sprintf("invalid raw argument %d: %v", i, err))
 		}
-		err = json.Unmarshal(raw, argval.Interface())
+		err = jjson.Unmarshal(raw, argval.Interface())
 		if err != nil {
 			return args, jsonrpc.NewInvalidParamsError(fmt.Sprintf("invalid argument %d: %v", i, err))
 		}
diff --git a/go.mod b/go.mod
index a548c85bfde972ab85a26358913950cbbb4c7281..50d74b46f969c36438852b32cae143ed73a62ae2 100644
--- a/go.mod
+++ b/go.mod
@@ -2,8 +2,6 @@ module gfx.cafe/open/jrpc
 
 go 1.21
 
-replace github.com/goccy/go-json v0.10.2 => github.com/elee1766/go-json v0.10.2-1
-
 require (
 	gfx.cafe/open/websocket v1.9.2
 	gfx.cafe/util/go/bufpool v0.0.0-20230721185457-c559e86c829c
@@ -11,7 +9,7 @@ require (
 	gfx.cafe/util/go/generic v0.0.0-20230721185457-c559e86c829c
 	github.com/davecgh/go-spew v1.1.1
 	github.com/go-faster/jx v1.1.0
-	github.com/goccy/go-json v0.10.2
+	github.com/json-iterator/go v1.1.12
 	github.com/stretchr/testify v1.8.4
 	golang.org/x/net v0.17.0
 	golang.org/x/sync v0.4.0
@@ -23,6 +21,8 @@ require (
 	github.com/go-faster/errors v0.6.1 // indirect
 	github.com/klauspost/compress v1.17.0 // indirect
 	github.com/kr/pretty v0.3.1 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
+	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/segmentio/asm v1.2.0 // indirect
 	golang.org/x/exp v0.0.0-20230206171751-46f607a40771 // indirect
diff --git a/go.sum b/go.sum
index e9b7c2dc9dfd0997b722d6d37de144795c5d167e..b251c09085d2d179c150af353d1af88d9183fa1b 100644
--- a/go.sum
+++ b/go.sum
@@ -9,10 +9,9 @@ gfx.cafe/util/go/generic v0.0.0-20230721185457-c559e86c829c/go.mod h1:WvSX4JsCRB
 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/elee1766/go-json v0.10.2-1 h1:AW2+8FAs2wVgRo90yz1l7pXKEiPxC71jquZNzgebkkc=
-github.com/elee1766/go-json v0.10.2-1/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
 github.com/go-faster/errors v0.6.1 h1:nNIPOBkprlKzkThvS/0YaX8Zs9KewLCOSFQS5BU06FI=
 github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+Jpi2LAyY=
 github.com/go-faster/jx v1.1.0 h1:ZsW3wD+snOdmTDy9eIVgQdjUpXRRV4rqW8NS3t+20bg=
@@ -20,6 +19,9 @@ github.com/go-faster/jx v1.1.0/go.mod h1:vKDNikrKoyUmpzaJ0OkIkRQClNHFX/nF3dnTJZb
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
 github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
 github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
 github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
@@ -30,6 +32,10 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -37,6 +43,8 @@ github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZV
 github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
 github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
 github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg=
diff --git a/pkg/jjson/json.go b/pkg/jjson/json.go
new file mode 100644
index 0000000000000000000000000000000000000000..5537beaf83d4f73a3c36e2f821a1d6cc1e019bb8
--- /dev/null
+++ b/pkg/jjson/json.go
@@ -0,0 +1,44 @@
+package jjson
+
+import (
+	"bytes"
+	"io"
+
+	jsoniter "github.com/json-iterator/go"
+)
+
+var jConfig = jsoniter.Config{
+	ValidateJsonRawMessage: false,
+	EscapeHTML:             false,
+	SortMapKeys:            true,
+}.Froze()
+
+func Encode(w io.Writer, v any) error {
+	s := jConfig.BorrowStream(w)
+	defer jConfig.ReturnStream(s)
+	s.WriteVal(v)
+	return s.Flush()
+}
+
+func Decode(r io.Reader, v any) error {
+	d := jConfig.NewDecoder(r)
+	return d.Decode(v)
+}
+
+func Unmarshal(xs []byte, v any) error {
+	d := jConfig.NewDecoder(bytes.NewBuffer(xs))
+	return d.Decode(v)
+}
+
+func Marshal(v any) ([]byte, error) {
+
+	out := &bytes.Buffer{}
+	s := jConfig.BorrowStream(out)
+	defer jConfig.ReturnStream(s)
+	s.WriteVal(v)
+	err := s.Flush()
+	if err != nil {
+		return nil, err
+	}
+	return out.Bytes(), nil
+}
diff --git a/pkg/jsonrpc/reqresp.go b/pkg/jsonrpc/reqresp.go
index 4959e25c0e88ecc1b716489628237fc9e88aeec6..3bd59ef358cecf63b6a8a74b7534dea9c5dbe9fb 100644
--- a/pkg/jsonrpc/reqresp.go
+++ b/pkg/jsonrpc/reqresp.go
@@ -2,8 +2,7 @@ package jsonrpc
 
 import (
 	"context"
-
-	json "github.com/goccy/go-json"
+	"encoding/json"
 )
 
 // http.ResponseWriter interface, but for jrpc
diff --git a/pkg/jsonrpc/wire.go b/pkg/jsonrpc/wire.go
index b844d5a353bf9229539eec956433c8d7f88af72d..38c1e7d84bd1282bc57919b572eb3f4d95cb1552 100644
--- a/pkg/jsonrpc/wire.go
+++ b/pkg/jsonrpc/wire.go
@@ -2,11 +2,12 @@ package jsonrpc
 
 import (
 	"bytes"
+	"encoding/json"
 	"fmt"
 	"reflect"
 	"strconv"
 
-	"github.com/goccy/go-json"
+	"gfx.cafe/open/jrpc/pkg/jjson"
 )
 
 // Version represents a JSON-RPC version.
@@ -137,12 +138,12 @@ func (id *ID) UnmarshalJSON(data []byte) error {
 	}
 	// it has to be a string or number
 	var num int
-	err := json.Unmarshal(data, &num)
+	err := jjson.Unmarshal(data, &num)
 	if err == nil {
 		return nil
 	}
 	var str string
-	err = json.Unmarshal(data, &str)
+	err = jjson.Unmarshal(data, &str)
 	if err == nil {
 		return nil
 	}
diff --git a/pkg/server/rw_batch.go b/pkg/server/rw_batch.go
index e102594ca7423aa43b80a84b84eea7974ed32b99..e5bb473db52c721ce79d392941d124ebc146b77b 100644
--- a/pkg/server/rw_batch.go
+++ b/pkg/server/rw_batch.go
@@ -3,10 +3,11 @@ package server
 import (
 	"bytes"
 	"context"
+	"encoding/json"
 	"sync"
 
+	"gfx.cafe/open/jrpc/pkg/jjson"
 	"gfx.cafe/open/jrpc/pkg/jsonrpc"
-	"github.com/goccy/go-json"
 )
 
 // batchingRespWriter is NOT thread safe
@@ -48,7 +49,7 @@ func (c *batchingRespWriter) Send(v any, e error) (err error) {
 	if v != nil && c.err == nil {
 		buf := &bytes.Buffer{}
 		w := newWriter(buf, maxBatchSizeBytes, false)
-		err = json.NewEncoder(w).Encode(v)
+		err = jjson.Encode(w, v)
 		if err != nil {
 			// the user just gets a generic error saying that the json is bad
 			c.err = jsonrpc.NewInternalError("server sent bad json")
diff --git a/pkg/server/server.go b/pkg/server/server.go
index 7ce37c85d7bffdd2498f415e3d6df3cb7eab58a1..dad905358967aaad91092a863f9a9d53bbd7121a 100644
--- a/pkg/server/server.go
+++ b/pkg/server/server.go
@@ -2,18 +2,19 @@ package server
 
 import (
 	"context"
+	"encoding/json"
 	"errors"
 	"io"
 	"sync"
 
 	"golang.org/x/sync/semaphore"
 
+	"gfx.cafe/open/jrpc/pkg/jjson"
 	"gfx.cafe/open/jrpc/pkg/jsonrpc"
 
 	"gfx.cafe/util/go/bufpool"
 
 	"github.com/go-faster/jx"
-	"github.com/goccy/go-json"
 )
 
 // Server is an RPC server.
@@ -330,9 +331,7 @@ func (c *callResponder) send(ctx context.Context, env *callEnv) (err error) {
 			case func(e *jx.Writer) error:
 				err = cast(enc)
 			default:
-				err = json.NewEncoder(w).EncodeWithOption(cast, func(eo *json.EncodeOption) {
-					eo.DisableNewline = true
-				})
+				err = jjson.Encode(w, cast)
 			}
 		} else {
 			enc.Null()
@@ -361,7 +360,7 @@ func (c *callResponder) notify(ctx context.Context, env *notifyEnv) (err error)
 	//  allocate a temp buffer for this packet
 	buf := bufpool.GetStd()
 	defer bufpool.PutStd(buf)
-	err = json.NewEncoder(buf).Encode(env.dat)
+	err = jjson.Encode(buf, env.dat)
 	if err != nil {
 		msg.Error = err
 	} else {
diff --git a/readme.md b/readme.md
index 6385cfd6990cbc0b6c112ea486e5a3784c98b22b..49fbdaf6f2c99e3b83c399bc8f3db939499c4ad2 100644
--- a/readme.md
+++ b/readme.md
@@ -22,7 +22,7 @@ it is currently being used in the oku.trade api in proxy, client, and server app
  - simple but powerful middleware framework
  - subscription framework used by go-ethereum/rpc is implemented as middleware.
  - http (with rest-like access via RPC verb), websocket, io.Reader/io.Writer (tcp, any net.Conn, etc), inproc codecs.
- - using faster json packages (goccy/go-json and jx)
+ - using faster json packages (jsoniter, jx)
  - extensions, which allow setting arbitrary fields on the parent object, like in sourcegraph jsonrpc2
  - jmux, which allows for http-like routing, implemented like `go-chi/v5`, except for jsonrpc2 paths
  - argreflect, which allows mounting methods on structs to the rpc engine, like go-ethereum/rpc