docs.unity3d.com
Search Results for

    Show / Hide Table of Contents

    Connect using a relay server

    Configure the NetworkDriverStore so that players can connect through Unity Relay when using a client-hosted setup.

    When you use a client-hosted architecture with no dedicated server deployment, players can't connect to the host directly, so they connect through a relay server instead. Unity Relay provides this connection, but the default Netcode for Entities driver setup isn't configured to use it out of the box. To enable Relay, configure the NetworkDriverStore yourself.

    You can configure the NetworkDriverStore either before or after the client and server worlds are created. It's recommended that you establish your service connections and perform any service-related operations that don't require a live connection before creating the client and server worlds, because it makes your workflows more contextual and leaves less world creation and disposal to undo if an error occurs. This isn't a strict requirement: you can create and dispose of client and server worlds at any time.

    This page assumes that you're familiar with Unity Relay. For background information and code examples, refer to the Relay documentation.

    Prerequisites

    Before you configure the NetworkDriverStore, complete the following:

    • Set up and connect to the Relay service, create an allocation, and obtain the Relay server data and the corresponding join code. For instructions, refer to the Relay documentation.

    Choose how to configure the driver

    There are two strategies for configuring the NetworkDriverStore to use Relay, which differ only in when you apply the configuration:

    • Use a custom driver constructor to configure Relay before the worlds are created. Use this strategy when you obtain the Relay allocation and join code before world creation.
    • Reset the driver store to configure Relay after the worlds are created. Use this strategy when your Relay data isn't available until after the worlds exist.

    Set up the driver with a custom INetworkDriverConstructor

    Use an INetworkStreamDriverConstructor to initialize the NetworkSettings with the Relay data before the worlds are created. For more information about custom driver constructors, refer to Customize network driver creation.

    To configure Relay before the client and server worlds are created:

    1. Set up the Relay service and obtain the Relay server data for the client and server.

    2. Create a driver constructor that initializes the NetworkSettings with the Relay data and passes it to NetworkStreamReceiveSystem.DriverConstructor. The following example supports both a local IPC connection for self-hosting and a Relay connection for remote or local clients:

      /// <summary>
      /// Register client and server using Relay server settings.
      /// For the client, if the Relay settings are not set and the modality is `Client/Server`, it will
      /// try to setup the driver using IPCNetworkInterface.
      /// </summary>
      public class RelayDriverConstructor : INetworkStreamDriverConstructor
      {
          RelayServerData m_RelayClientData;
          RelayServerData m_RelayServerData;
      
          public RelayDriverConstructor(RelayServerData serverData, RelayServerData clientData)
          {
              m_RelayServerData = serverData;
              m_RelayClientData = clientData;
          }
      
          /// <summary>
          /// This method will ensure that we register different driver types based on the Relay settings
          /// settings.
          /// <para>
          /// Mode          |  Relay Settings
          /// Client/Server |  Valid -> use Relay to connect to local server
          ///                  Invalid -> use IPC to connect to local server
          /// Client        |  Always use Relay. Expect data to be valid, or exceptions are thrown by Transport.
          /// <para>
          /// <para>
          /// For WebGL, WebSocket is always preferred for client in the Editor, to closely emulate the player behaviour.
          /// </para>
          /// </summary>
          public void CreateClientDriver(NetcodeWorld world, ref NetworkDriverStore driverStore, NetDebug netDebug)
          {
              var settings = DefaultDriverBuilder.GetNetworkClientSettings();
              //if the Relay data is not valid, connect via local IPC
              if(ClientServerBootstrap.RequestedPlayType == ClientServerBootstrap.PlayType.ClientAndServer &&
                 !m_RelayClientData.Endpoint.IsValid)
              {
                  DefaultDriverBuilder.RegisterClientIpcDriver(world, ref driverStore, netDebug, settings);
              }
              else
              {
                  settings.WithRelayParameters(ref m_RelayClientData);
      #if !UNITY_WEBGL
                  DefaultDriverBuilder.RegisterClientUdpDriver(world, ref driverStore, netDebug, settings);
      #else
                  DefaultDriverBuilder.RegisterClientWebSocketDriver(world, ref driverStore, netDebug, settings);
      #endif
              }
          }
      
          public void CreateServerDriver(NetcodeWorld world, ref NetworkDriverStore driverStore, NetDebug netDebug)
          {
              //The first driver is the IPC for internal client/server connection if necessary.
              // IPC can't use Relay and needs to be set up without Relay data.
              var ipcSettings = DefaultDriverBuilder.GetNetworkServerSettings();
              DefaultDriverBuilder.RegisterServerIpcDriver(world, ref driverStore, netDebug, ipcSettings);
              var relaySettings = DefaultDriverBuilder.GetNetworkServerSettings();
              //The other driver (still the same port) is going to listen using Relay for external connections.
              relaySettings.WithRelayParameters(ref m_RelayServerData);
      #if !UNITY_WEBGL
              DefaultDriverBuilder.RegisterServerUdpDriver(world, ref driverStore, netDebug, relaySettings);
      #else
              DefaultDriverBuilder.RegisterServerWebSocketDriver(world, ref driverStore, netDebug, relaySettings);
      #endif
          }
      }
      
    3. Assign the constructor to NetworkStreamReceiveSystem.DriverConstructor before the bootstrap creates the worlds.

    After the worlds are created, the host listens for remote clients through Relay, and clients connect through Relay or through a local IPC connection when self-hosting. For a complete example, refer to the Relay sample.

    Set up the driver by resetting the NetworkDriverStore

    Reset the driver store to apply the same Relay configuration after the worlds already exist. This strategy is almost identical to using a custom driver constructor; the difference is that you perform the initialization after world creation. For more information, refer to Reset the NetworkDriverStore setup.

    To configure Relay after the worlds are created:

    1. Create a new NetworkDriverStore and register the client or server drivers with the Relay server data.

    2. Call NetworkStreamDriver.ResetDriverStore on the relevant world to apply the new driver store. The following example resets the driver store for the client and server worlds:

              public void SetupClientWorld(NetcodeWorld world, ref RelayServerData relay)
              {
                  //we assume here we want to forcibly use Relay
                  var settings = DefaultDriverBuilder.GetNetworkClientSettings();
                  settings.WithRelayParameters(ref relay);
                  var netDebug = world.EntityManager.CreateEntityQuery(typeof(NetDebug)).GetSingleton<NetDebug>();
                  var driverStore = new NetworkDriverStore();
                  DefaultDriverBuilder.RegisterClientUdpDriver(world, ref driverStore, netDebug, settings);
                  var networkStreamDriver = world.EntityManager.CreateEntityQuery(typeof(NetworkStreamDriver)).GetSingleton<NetworkStreamDriver>();
                  networkStreamDriver.ResetDriverStore(world.Unmanaged, ref driverStore);
              }
      
              public void SetupServerWorld(NetcodeWorld world, ref RelayServerData relay)
              {
                  var driverStore = new NetworkDriverStore();
                  var netDebug = world.EntityManager.CreateEntityQuery(typeof(NetDebug)).GetSingleton<NetDebug>();
                  var ipcSettings = DefaultDriverBuilder.GetNetworkServerSettings();
                  DefaultDriverBuilder.RegisterServerIpcDriver(world, ref driverStore, netDebug, ipcSettings);
                  var relaySettings = DefaultDriverBuilder.GetNetworkServerSettings();
                  //The other driver (still the same port) is going to listen using relay for external conections.
                  relaySettings.WithRelayParameters(ref relay);
      #if !UNITY_WEBGL
                  DefaultDriverBuilder.RegisterServerUdpDriver(world, ref driverStore, netDebug, relaySettings);
      #else
                  DefaultDriverBuilder.RegisterServerWebSocketDriver(world, ref driverStore, netDebug, relaySettings);
      #endif
                  var networkStreamDriver = world.EntityManager.CreateEntityQuery(typeof(NetworkStreamDriver)).GetSingleton<NetworkStreamDriver>();
                  networkStreamDriver.ResetDriverStore(world.Unmanaged, ref driverStore);
              }
      

    After you reset the driver store, the world uses the Relay drivers for subsequent connections.

    Additional resources

    • Netcode for Entities multi-driver architecture
    • Client-hosted
    • Relay documentation
    • Relay sample
    In This Article
    Back to top
    Copyright © 2026 Unity Technologies — Trademarks and terms of use
    • Legal
    • Privacy Policy
    • Cookie Policy
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)