Migration to 0.8.0
Edit pageLast modified: 25 June 2025Version 0.8.0
brings a lot of changes, mainly targeted to remove inherently broken functionality and simplify kRPC protocol where possible. This is reflected in the number of breaking changes and deprecations.
This page aims to cover all such changes and associated migration instructions.
Strict mode enforcement
Strict mode is now enforced and can't be disabled. See Strict mode for detailed migrations.
kRPC protocol changes
The following changes are reflected in the kRPC protocol on the wire:
KrpcServer
doesn't send CANCELLATION_ACK messages anymore.KrpcClient
sends REQUEST cancellation messages for every individually finished call, canceled or finished successfully
Though changes should not affect most users, for those who like to look at the wire it might be useful to know.
Behavioral changes
Some changes in the behavior of kRPC clients and servers:
Lifetime for client-side streams is changed.
Previously, the stream scopes bounded client-side streams. However, stream scopes are completely removed now, so the client-side streams lifetime is now bound to the request's lifetime. This means that when the function returns, every client stream is closed.
Serial format is now only constructed once per client.
Previously, the serial format was constructed once per RPC call. The serial format can be passed using the
KrpcConfig
. And the builder code was executed once per every call.Now this behavior is removed. The serial format is constructed once per client.
Services are now instantiated once per service type (Rpc FQ name) and not once per client-side instance.
Services lost their CoroutineScopes (see Incompatible API changes). That means that there are no individual lifetimes for each service instance now. Instead, now each service stub on a client is merely a proxy for function calls. And on the server side, the service implementation is instantiated once per service type. To control this behavior more granularly on the server, new
deregisterService
function is introduced.tip
For kRPC servers, the factory function for service instances is now executed once per service type:
rpcServer.registerService<MyService> { MyServiceImpl() }
Handshake is now cold.
Previously, the handshake was executed on client creation. Now, the handshake is executed on the first RPC request.
Incompatible API changes
RpcClient.callServerStreaming
lost its default implementation:Before
interface RpcClient {fun <T> callServerStreaming(call: RpcCall): Flow<T> {error("Not implemented")}}After
interface RpcClient {fun <T> callServerStreaming(call: RpcCall): Flow<T>}@Rpc
services lost their CoroutineScope:Before
val service = client.withService<MyService>()assert(service is CoroutineScope) // OKAfter
val service = client.withService<MyService>()assert(service is CoroutineScope) // failRpcClient
lost itsCoroutineScope
:Before
interface RpcClient : CoroutineScopeAfter
interface RpcClientRpcServer
lost itsCoroutineScope
:Before
interface RpcServer : CoroutineScopeAfter
interface RpcServerRpcServer.registerService
factory
parameter changes type from(CoroutineContext) -> Service
to() -> Service
:Before
interface RpcServer {fun <@Rpc Service : Any> registerService(serviceKClass: KClass<Service>,serviceFactory: (CoroutineContext) -> Service,)}inline fun <@Rpc reified Service : Any> RpcServer.registerService(noinline serviceFactory: (CoroutineContext) -> Service,) {registerService(Service::class, serviceFactory)}After
interface RpcServer {fun <@Rpc Service : Any> registerService(serviceKClass: KClass<Service>,serviceFactory: () -> Service,)}inline fun <@Rpc reified Service : Any> RpcServer.registerService(noinline serviceFactory: () -> Service,) {registerService(Service::class, serviceFactory)}RpcServer.registerService
lost itsCoroutineContext
parameter:Before
interface RpcServerAfter
interface RpcServer {fun <@Rpc Service : Any> deregisterService(serviceKClass: KClass<Service>,)}RpcCall
changed parameter name and type for function's data:Before
class RpcCall(val descriptor: RpcServiceDescriptor<*>,val callableName: String,val data: Any?,val serviceId: Long,)After
class RpcCall(val descriptor: RpcServiceDescriptor<*>,val callableName: String,val parameters: Array<Any?>,val serviceId: Long,)For Ktor,
HttpClient.rpc
extension function is now non-suspendable.KtorRpcClient.webSocketSession
is now wrapped in Deferred:Before
interface KtorRpcClient : RpcClient {val webSocketSession: WebSocketSession}After
interface KtorRpcClient : RpcClient {val webSocketSession: Deferred<WebSocketSession>}KrpcClient
abstract class has two new abstract methods:initializeConfig
andinitializeTransport
. They can be used to delay transport initialization until the first RPC call.To mimic old behavior,
InitializedKrpcClient
can be used:Before
class MyClient(config: KrpcConfig,transport: KrpcTransport,) : KrpcClient(config, transport)After
class MyClient(config: KrpcConfig,transport: KrpcTransport,) : InitializedKrpcClient(config, transport)
API removals
The following APIs are removed:
kotlinx.rpc.RpcClient.callAsync
- previously deprecatedkotlinx.rpc.RpcClient.provideStubContext
kotlinx.rpc.registerPlainFlowField
- previously deprecatedkotlinx.rpc.registerSharedFlowField
- previously deprecatedkotlinx.rpc.registerStateFlowField
- previously deprecatedkotlinx.rpc.awaitFieldInitialization
- previously deprecatedkotlinx.rpc.UninitializedRpcFieldException
- previously deprecatedkotlinx.rpc.UninitializedRPCFieldException
- previously deprecatedkotlinx.rpc.RpcEagerField
- previously deprecatedkotlinx.rpc.RPCCall
- previously deprecated aliaskotlinx.rpc.RPCClient
- previously deprecated aliaskotlinx.rpc.descriptor.RpcInvokator.Field
- previously deprecatedkotlinx.rpc.descriptor.RpcServiceDescriptor.getFields
- previously deprecatedkotlinx.rpc.krpc.StreamScope
- previously deprecatedkotlinx.rpc.krpc.streamScoped
- previously deprecatedkotlinx.rpc.krpc.withStreamScope
- previously deprecatedkotlinx.rpc.krpc.invokeOnStreamScopeCompletion
- previously deprecatedkotlinx.rpc.krpc.KrpcConfigBuilder.SharedFlowParametersBuilder
- previously deprecatedkotlinx.rpc.krpc.KrpcConfigBuilder.sharedFlowParameters
- previously deprecatedkotlinx.rpc.krpc.KrpcConfig.sharedFlowBuilder
- previously deprecatedkotlinx.rpc.krpc.RPCTransport
- previously deprecated aliaskotlinx.rpc.krpc.RPCTransportMessage
- previously deprecated aliaskotlinx.rpc.krpc.RPCConfigBuilder
- previously deprecated aliaskotlinx.rpc.krpc.client.KRPCClient
- previously deprecated aliaskotlinx.rpc.krpc.server.RPCServer
- previously deprecated aliaskotlinx.rpc.krpc.server.KRPCServer
- previously deprecated aliaskotlinx.rpc.krpc.serialization.RPCSerialFormat
- previously deprecated aliaskotlinx.rpc.krpc.serialization.RPCSerialFormatBuilder
- previously deprecated aliaskotlinx.rpc.krpc.serialization.RPCSerialFormatConfiguration
- previously deprecated aliaskotlinx.rpc.krpc.ktor.client.RPC
- previously deprecated aliaskotlinx.rpc.krpc.ktor.client.installRPC
- previously deprecated aliaskotlinx.rpc.krpc.ktor.server.RPC
- previously deprecated aliaskotlinx.rpc.krpc.ktor.server.RPCRoute
- previously deprecated alias
Deprecations
Gradle's
rpc.strict
extension is deprecated with an error. Strict mode is now enforced and can't be disabled. See Strict mode for detailed migrations.RemoteService
is deprecated with error; services are no longer having this interface added during the compilation. See Behavioral changes for services' lifetime information.
Other changes
MISSING_RPC_ANNOTATION
compiler inspection is removed.ABI incompatible change:
KrpcTransport.receiveCatching
is now an extension function.The following compiler plugin options are removed:
strict-stateFlow
strict-sharedFlow
strict-nested-flow
strict-stream-scope
strict-suspending-server-streaming
strict-not-top-level-server-flow
strict-fields