Skip to content

(guide) how to deploy a global contract #2663

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b93e776
Update yarn.lock
bucanero Jul 15, 2025
0c9a344
update
bucanero Jul 15, 2025
b6cad50
update
bucanero Jul 16, 2025
b4a1834
Merge branch 'master' into 2565-doc-section-on-global-contracts
bucanero Jul 16, 2025
6299444
Update near-api.md
bucanero Jul 17, 2025
49ebb32
Update global-contracts.md
bucanero Jul 17, 2025
36982d0
Merge branch 'master' into 2565-doc-section-on-global-contracts
bucanero Jul 18, 2025
52d31ec
Merge branch 'master' into 2565-doc-section-on-global-contracts
bucanero Jul 22, 2025
81e3927
Merge branch 'master' into 2565-doc-section-on-global-contracts
bucanero Jul 28, 2025
6eb51fd
Update near-api.md
bucanero Jul 28, 2025
7be4162
Squashed commit of the following:
bucanero Jul 29, 2025
9cc38a6
Merge branch 'master' into 2565-doc-section-on-global-contracts
bucanero Jul 29, 2025
17c36ff
Merge branch 'master' into 2628-guide-how-to-deploy-a-global-contract
bucanero Jul 29, 2025
3e76e1f
update
bucanero Jul 29, 2025
cd6733e
Merge branch '2565-doc-section-on-global-contracts' into 2628-guide-h…
bucanero Jul 29, 2025
20eec80
Update global-contracts.md
bucanero Jul 30, 2025
1438f1e
Update global-contracts.md
bucanero Jul 30, 2025
3cf57c3
Update global-contracts.md
bucanero Jul 30, 2025
8fbca75
Merge branch '2565-doc-section-on-global-contracts' into 2628-guide-h…
bucanero Jul 30, 2025
aa0a906
add tutorial
bucanero Jul 31, 2025
4a836f8
tutorial
bucanero Jul 31, 2025
c58cf56
Update global-contracts.md
bucanero Jul 31, 2025
891d360
Update global-contracts.md
bucanero Aug 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 72 additions & 37 deletions docs/smart-contracts/global-contracts.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,99 @@
---
id: global-contracts
title: Global Contracts
sidebar_label: Global Contracts
sidebar_label: Introduction
description: "Global contracts allow smart contracts to be deployed once and reused by any account without incurring high storage costs."
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

Global contracts allow smart contracts to be deployed once and reused by any account without incurring high storage costs.
Rather than deploying duplicate contracts or routing messages inefficiently across shards, NEAR developers can now think modularly and universally: write once, use everywhere.

---
## Overview

## Deploying a Global Contract
If you've ever deployed the same contract code to multiple accounts, you’ve likely noticed that each deployment requires you to pay the full storage cost again — since the size of the WASM file determines how much `NEAR` is locked on the account.
With [NEP-0591](https://github.com/near/NEPs/blob/master/neps/nep-0591.md), which introduces Global Contracts, NEAR provides a highly strategic alternative that [solves this elegantly](#solution).

Global contracts can be deployed in 2 ways: either by their hash or by the owner account ID.
Contracts deployed by hash are effectively immutable and cannot be updated.
When deployed by account id the owner can redeploy the contract updating it for all its users.
## Key Features

These are the features that make Global Contracts special:

- **Global Addressing**: These contracts are not tied to a specific account but instead use a unique global identifier. This enables any contract, user, or application on NEAR to call the contract from any shard instantly.

- **Immutable Logic**: The contract code is fixed once deployed, making it a trusted point of reference. This ensures consistency and security—ideal for system-critical protocols.

- **Shared Infrastructure**: Global contracts can act as canonical libraries, utility hubs, or standards for other contracts to rely on, simplifying development and reducing duplication.

Global contracts can be deployed using `NEAR CLI`.
The process is similar to [deploying a regular contract](./release/deploy.md#deploying-the-contract) but `deploy-as-global` command should be used instead of `deploy`.
- **Cross-Shard Superpowers**: Developers can build truly modular apps where parts of their stack reside on different shards but communicate via shared global logic with minimal latency or duplication.

<Tabs groupId="cli-tabs">
<TabItem value="by-hash" label="By Hash">
### Use Cases

```bash
near contract deploy-as-global use-file <route_to_wasm> as-global-hash <account_id> network-config testnet sign-with-keychain send
```
</TabItem>
- **Standard Libraries**: Reusable components for math, string operations, or token interfaces.
- **DeFi Protocols**: Global contracts can anchor DEXs, lending markets, oracles—shared across all applications.
- **DAO Frameworks**: Shared governance modules that any DAO can plug into, ensuring consistency and reliability.
- **Identity & Credentials**: One global contract can manage decentralized identity verification and access management for the entire chain.
- **Multi-part dApps**: Complex applications can split responsibilities across shards while accessing a common logic core.

<TabItem value="by-account-id" label="By Account Id">
## Solution

Global Contracts solve the inefficiency of duplicate deployments by allowing the same contract code to be shared across multiple accounts, so storage cost is paid only once.

There are two ways to reference a global contract:
- **[By Account](#reference-by-account)**: an upgradable contract is published globally under a specific account ID.
- **[By Hash](#reference-by-hash)**: an immutable contract is deployed globally and identified by its code hash.

```bash
near contract deploy-as-global use-file <route_to_wasm> as-global-account-id <account_id> network-config testnet sign-with-keychain send
```
</TabItem>
</Tabs>

:::info
Note that deploying a global contract incurs high storage costs. Tokens are burned to compensate for storing the contract on-chain, unlike regular contracts where tokens are locked based on contract size.
- The contract code is distributed across all shards in the Near Protocol network, not stored inside any specific account’s storage.
- The account is charged 10x more for deploying a Global Contract, at the rate 10 NEAR per 100KB.
- This amount is entirely burnt and cannot be recovered later, unlike regular deployments where Near is simply locked.
- The total fee is typically under 0.001 NEAR for a user to use a Global Contract, since only a few bytes are needed for the reference that is stored in the account's storage.
:::

## Using a Global Contract
### Reference by Account

When using a reference **by account**, the contract code is tied to another account. If that account later deploys a new version of the contract, your account will automatically start using the updated code, with no need for redeployment.

### Reference by Hash

When using a reference **by hash**, you reference the global contract by its immutable code hash. This ensures you're always using the exact same version, and it will never change unless you explicitly redeploy with a different hash.

## When to use Global Contracts

A previously deployed global contract can be attached to any NEAR account using `NEAR CLI` `deploy` command. Such a contract behaves exactly like a regular contract.
Ask yourself the following questions before deciding how to deploy your contracts:

<Tabs groupId="cli-tabs">
<TabItem value="by-hash" label="By Hash">
- **_Are you working in a local environment?_**

If you're just testing or building a prototype, [regular deployments](release/deploy.md) are simpler and more flexible. There's no need to burn tokens or register global references — just deploy and iterate.

```bash
# Using global contract deployed by <global_contract_hash> hash
near contract deploy <account_id> use-global-hash <global_contract_hash> without-init-call network-config testnet
```
</TabItem>
- **_Is the contract supposed to be deployed on many accounts?_**

<TabItem value="by-account-id" label="By Account Id">
If the same contract will be reused across many independent accounts — say, 10 or more — Global Contracts can significantly reduce overall cost and complexity. But if only a few accounts are involved, regular deployment remains the more economical choice.

```bash
# Using global contract deployed by <global_contract_account_id> account id
near contract deploy <account_id> use-global-account-id <global_contract_account_id> without-init-call network-config testnet
```
</TabItem>
</Tabs>
- **_Are these accounts managed by your team?_**

If all target accounts are under your infrastructure, you may prefer regular deployments for flexibility and cost recovery.
- **_Are there more than 10 accounts?_**

Global Contracts become financially efficient when reused at scale. If you're deploying the same contract to more than 10 accounts, it's likely worth considering.

- **_Do you need to upgrade the contract across many accounts in one step, even if it requires burning tokens?_**

If you want to be able to push updates to all deployed instances at once, then go with Global Contracts by Account ID, but keep in mind that the deployment cost is non-refundable.

- **_Does your use case require the contract to be permanently immutable?_**

If the contract must never change, for example, due to security, compliance, or user trust, then using a Global Contract by Code Hash ensures immutability at the protocol level.

## Deploying a Global Contract

Global contracts can be deployed in 2 ways: either by their [hash](#reference-by-hash) or by the owner [account ID](#reference-by-account).
Contracts deployed by hash are effectively immutable and cannot be updated.
When deployed by account ID the owner can redeploy the contract updating it for all its users.

Global contracts can be deployed using [`NEAR CLI`](#) or by code using [NEAR APIs](#).

:::info
Note that deploying a global contract incurs high storage costs. Tokens are burned to compensate for storing the contract on-chain, unlike regular contracts where tokens are locked based on contract size.
:::
156 changes: 142 additions & 14 deletions docs/tools/near-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1167,13 +1167,11 @@ Unlike many other blockchains, contracts on NEAR are mutable, meaning you have t

### Deploy a Global Contract {#deploy-a-global-contract}

If you've ever deployed the same contract code to multiple accounts, you’ve likely noticed that each deployment requires you to pay the full storage cost again — since the size of the WASM file determines how much `NEAR` is locked on the account.

Global Contracts solve this inefficiency by allowing the same contract code to be shared across multiple accounts, so storage cost is paid only once.
[Global contracts](../smart-contracts/global-contracts.md) allow smart contracts to be deployed once and reused by any account without incurring high storage costs.

There are two ways to reference a global contract:
- **By account:** The contract code is tied to another account. If that account later deploys a new version of the contract, your account will automatically start using the updated code, with no need for redeployment.
- **By hash:** You reference the contract by its immutable code hash. This ensures you're always using the exact same version, and it will never change unless you explicitly redeploy with a different hash.
- **[By account](../smart-contracts/global-contracts.md#reference-by-account):** The contract code is tied to another account.
- **[By hash](../smart-contracts/global-contracts.md#reference-by-hash):** You reference the contract by its immutable code hash.

<Tabs groupId="api">
<TabItem value="js" label="🌐 JavaScript">
Expand All @@ -1196,14 +1194,6 @@ There are two ways to reference a global contract:
await account.deployGlobalContract(wasm, "accountId");
```

Once the global contract is deployed, let’s see how an end user can reference and use it in their own account. To do this, they need to call the `useGlobalContract` function and pass the source `accountId` where the contract was originally deployed.

```js
const account = new Account("another_user.testnet", provider, signer);

await account.useGlobalContract({ accountId: "user.testnet" });
```

<a href="https://github.com/near-examples/near-api-examples/blob/main/javascript/examples/deploy-global-contract-by-account.js" target="_blank" rel="noreferrer noopener" class="text-center">
See full example on GitHub
</a>
Expand All @@ -1224,7 +1214,96 @@ There are two ways to reference a global contract:
await account.deployGlobalContract(wasm, "codeHash");
```

Once the global contract is deployed, let’s see how an end user can reference and use it in their own account. To do this, they need to call the `useGlobalContract` function and pass the source `codeHash` of the original contract.
<a href="https://github.com/near-examples/near-api-examples/blob/main/javascript/examples/deploy-global-contract-by-hash.js" target="_blank" rel="noreferrer noopener" class="text-center">
See full example on GitHub
</a>
</TabItem>
</Tabs>

</TabItem>

<TabItem value="rust" label="🦀 Rust">

Once you've created an Account instance, you can deploy your regular contract as a global contract.

<Tabs>
<TabItem value="account" label="By Account" default>

Let’s look at an example of deploying a global contract by account.

To do this, use the `deploy_global_contract_code` function and use the method `as_account_id`, along with the contract’s code bytes.

```rust
let global_account_id: AccountId = "nft-contract.testnet".parse().unwrap();
let code = std::fs::read("path/to/your/contract.wasm").unwrap();
let signer = Signer::new(Signer::from_secret_key(private_key)).unwrap();

let result: FinalExecutionOutcomeView = Contract::deploy_global_contract_code(code)
.as_account_id(global_account_id)
.with_signer(signer)
.send_to_testnet()
.await.unwrap();
```

<a href="https://github.com/near-examples/near-api-examples/blob/main/rust/examples/global_contract_accountid.rs" target="_blank" rel="noreferrer noopener" class="text-center">
See full example on GitHub
</a>
</TabItem>

<TabItem value="hash" label="By Hash" default>

Let’s look at an example of deploying a global contract by hash.

To do this, use the `deploy_global_contract_code` function and use the method `as_hash`, along with the contract’s code bytes.

```rust
let account_id: AccountId = "my-account.testnet".parse().unwrap();
let code = std::fs::read("path/to/your/contract.wasm").unwrap();
let signer = Signer::new(Signer::from_secret_key(private_key)).unwrap();

let result: FinalExecutionOutcomeView = Contract::deploy_global_contract_code(code)
.as_hash()
.with_signer(account_id, signer)
.send_to_testnet()
.await.unwrap();
```

<a href="https://github.com/near-examples/near-api-examples/blob/main/rust/examples/global_contract_hash.rs" target="_blank" rel="noreferrer noopener" class="text-center">
See full example on GitHub
</a>
</TabItem>
</Tabs>

</TabItem>

</Tabs>

### Use a Global Contract

Once a [global contract](../smart-contracts/global-contracts.md) has been [deployed](#deploy-a-global-contract), let’s see how you can reference and use it from another account.

<Tabs groupId="api">
<TabItem value="js" label="🌐 JavaScript">

<Tabs>
<TabItem value="account" label="By Account" default>

To reference a global contract by account, you need to call the `useGlobalContract` function and pass the source `accountId` where the contract was originally deployed.

```js
const account = new Account("another_user.testnet", provider, signer);

await account.useGlobalContract({ accountId: "user.testnet" });
```

<a href="https://github.com/near-examples/near-api-examples/blob/main/javascript/examples/deploy-global-contract-by-account.js" target="_blank" rel="noreferrer noopener" class="text-center">
See full example on GitHub
</a>
</TabItem>

<TabItem value="hash" label="By Hash" default>

To reference a global contract by hash, you need to call the `useGlobalContract` function and pass the source `codeHash` of the original contract.

```js
const account = new Account("another_user.testnet", provider, signer);
Expand All @@ -1240,9 +1319,58 @@ There are two ways to reference a global contract:
</TabItem>
</Tabs>

</TabItem>

<TabItem value="rust" label="🦀 Rust">

<Tabs>
<TabItem value="account" label="By Account" default>

To reference a global contract by account, you need to call the `use_global_account_id` function and pass the source `accountId` where the contract was originally deployed.

```rust
let global_account_id: AccountId = "nft-contract.testnet".parse().unwrap();
let my_account_id: AccountId = "my-contract.testnet".parse().unwrap();
let my_signer = Signer::new(Signer::from_secret_key(private_key)).unwrap();

let result: FinalExecutionOutcomeView = Contract::deploy(my_account_id)
.use_global_account_id(global_account_id)
.without_init_call()
.with_signer(my_signer)
.send_to_testnet()
.await.unwrap();
```

<a href="https://github.com/near-examples/near-api-examples/blob/main/rust/examples/global_contract_accountid.rs" target="_blank" rel="noreferrer noopener" class="text-center">
See full example on GitHub
</a>
</TabItem>

<TabItem value="hash" label="By Hash" default>

To reference a global contract by hash, you need to call the `use_global_hash` function and pass the source `hash` of the original contract.

```rust
let global_hash: types::CryptoHash = "DxfRbrjT3QPmoANMDYTR6iXPGJr7xRUyDnQhcAWjcoFF".parse().unwrap();
let account_id: AccountId = "my-contract.testnet".parse().unwrap();
let signer = Signer::new(Signer::from_secret_key(private_key)).unwrap();

let result: FinalExecutionOutcomeView = Contract::deploy(account_id)
.use_global_hash(global_hash)
.without_init_call()
.with_signer(signer)
.send_to_testnet()
.await.unwrap();
```

<a href="https://github.com/near-examples/near-api-examples/blob/main/rust/examples/global_contract_hash.rs" target="_blank" rel="noreferrer noopener" class="text-center">
See full example on GitHub
</a>
</TabItem>
</Tabs>

</TabItem>

</Tabs>

---
Expand Down
Loading
Loading