diff --git a/docs/pages/config.mdx b/docs/pages/config.mdx
index e87a499fa9..d251fd99ad 100644
--- a/docs/pages/config.mdx
+++ b/docs/pages/config.mdx
@@ -121,3 +121,7 @@ The global configuration keys are all optional.
- **`worldsFile`** a `string`: JSON file for the chain to `World` deploy address mapping.
The default is `./worlds.json`.
+
+ -
+ **`upgradeableWorldImplementation`** a `bool`: Whether the `World` is to be deployed behind a proxy to [enable upgrades
+ of the core World implementation](/world/upgrade). The default is `false`.
diff --git a/docs/pages/world/_meta.js b/docs/pages/world/_meta.js
index 655c9a21d5..506ec2a1df 100644
--- a/docs/pages/world/_meta.js
+++ b/docs/pages/world/_meta.js
@@ -9,6 +9,7 @@ export default {
balance: "Balance",
"account-delegation": "Account Delegation",
"batch-calls": "Batch Calls",
+ "upgrade": "Upgrading",
modules: "Modules",
reference: "Reference",
};
diff --git a/docs/pages/world/upgrade.mdx b/docs/pages/world/upgrade.mdx
new file mode 100644
index 0000000000..fc3ea7597d
--- /dev/null
+++ b/docs/pages/world/upgrade.mdx
@@ -0,0 +1,95 @@
+import { CollapseCode } from "../../components/CollapseCode";
+import { Callout } from "nextra/components";
+
+# Upgrading worlds
+
+The [`System`s](./systems) can be upgraded without changing the underlying `World` code.
+However, if the `World` was deployed [behind a proxy](/config#upgradeableWorldImplementation) it is also possible to upgrade the `World` itself.
+This allows you to upgrade to a future version of MUD, but adds some gas overhead for all calls (due to one more level of indirection).
+
+## Are upgrades possible?
+
+As per [ERC-1967](https://eips.ethereum.org/EIPS/eip-1967#logic-contract-address), the storage slot `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` stores the address of the `World` implementation in a proxy.
+So to identify if a `World` is deployed behind a proxy run these commands:
+
+```sh copy
+WORLD_ADDRESS=0xbe6b85dc88f969e45d8d8ae128c5a9c9744d6464
+cast implementation $WORLD_ADDRESS
+```
+
+If the answer is anything other than zero, the `World` is behind a proxy and can be upgraded.
+
+## Performing an upgrade
+
+To upgrade the `World` use these steps in a `package/contracts` directory:
+
+1. Edit `.env` to add `WORLD_ADDRESS` with the address displayed by MUD Dev Tools.
+ For example, you might want to use this file:
+
+
+
+ ```sh filename=".env" showLineNumbers copy {12}
+ # This .env file is for demonstration purposes only.
+ #
+ # This should usually be excluded via .gitignore and the env vars attached to
+ # your deployment environment, but we're including this here for ease of local
+ # development. Please do not commit changes to this file!
+ #
+ # Enable debug logs for MUD CLI
+ DEBUG=mud:*
+ #
+ # Anvil default private key:
+ PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
+ WORLD_ADDRESS=0xbe6b85dc88f969e45d8d8ae128c5a9c9744d6464
+ ```
+
+
+
+1. Create this script in `scripts/UpgradeWorld.s.sol`.
+
+
+
+ ```solidity filename="UpgradeWorld.s.sol" copy showLineNumbers {18,23}
+ // SPDX-License-Identifier: MIT
+ pragma solidity >=0.8.24;
+
+ import { Script } from "forge-std/Script.sol";
+ import { console } from "forge-std/console.sol";
+
+ import { World } from "@latticexyz/world/src/World.sol";
+ import { WorldProxy } from "@latticexyz/world/src/WorldProxy.sol";
+
+ contract SetImplementation is Script {
+ function run() external {
+ uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
+ vm.startBroadcast(deployerPrivateKey);
+
+ address proxyAddress = vm.envAddress("WORLD_ADDRESS");
+
+ // Deploy new world implementation
+ World newWorld = new World();
+
+ console.log("proxy:", proxyAddress);
+ console.log("new World:", address(newWorld));
+
+ WorldProxy(payable(proxyAddress)).setImplementation(address(newWorld));
+
+ vm.stopBroadcast();
+ }
+ }
+ ```
+
+
+
+1. Run the script.
+
+ ```sh copy
+ forge script script/UpgradeWorld.s.sol --rpc-url http://localhost:8545 --broadcast
+ ```
+
+1. See the new address.
+
+ ```sh copy
+ source .env
+ cast implementation $WORLD_ADDRESS
+ ```