> ## Documentation Index
> Fetch the complete documentation index at: https://docs.near.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Reducing Contract Size

> Learn strategies to reduce NEAR smart contract size for optimized deployment and performance.

export const Github = ({url, start, end, fname, withSourceLink = true}) => {
  const [code, setCode] = useState(null);
  function toRaw(ref) {
    const fullUrl = ref.slice(ref.indexOf('https'));
    const [url] = fullUrl.split('#');
    const [org, repo, , branch, ...pathSeg] = new URL(url).pathname.split('/').slice(1);
    return `https://raw.githubusercontent.com/${org}/${repo}/${branch}/${pathSeg.join('/')}`;
  }
  async function fetchCode(url, fromLine, toLine) {
    let res;
    if (typeof window !== 'undefined') {
      const validUntil = localStorage.getItem(`${url}-until`);
      if (validUntil && Number(validUntil) > Date.now()) {
        res = localStorage.getItem(url);
      }
    }
    if (!res) {
      try {
        res = await (await fetch(url)).text();
        if (typeof window !== 'undefined') {
          localStorage.setItem(url, res);
          localStorage.setItem(`${url}-until`, String(Date.now() + 60000));
        }
      } catch {
        return 'Error fetching code, please try reloading';
      }
    }
    let body = res.split('\n');
    const from = fromLine ? Number(fromLine) - 1 : 0;
    const to = toLine ? Number(toLine) : body.length;
    body = body.slice(from, to);
    const precedingSpace = body.reduce((prev, line) => {
      if (line.length === 0) return prev;
      const spaces = line.match(/^\s+/);
      if (spaces) return Math.min(prev, spaces[0].length);
      return 0;
    }, Infinity);
    return body.map(line => line.slice(precedingSpace === Infinity ? 0 : precedingSpace)).join('\n');
  }
  function buildSourceUrl(url, start, end) {
    const base = url.split('#')[0];
    if (start && end) return `${base}#L${start}-L${end}`;
    if (start) return `${base}#L${start}`;
    return base;
  }
  useEffect(() => {
    const rawUrl = toRaw(url);
    fetchCode(rawUrl, start, end).then(res => setCode(res));
  }, [url, start, end]);
  const sourceUrl = buildSourceUrl(url, start, end);
  const startLine = start ? Number(start) : 1;
  const fileName = fname ?? sourceUrl.split('/').pop();
  return <div className="rounded-[0.625rem] border border-[#d0d7de] dark:border-[#30363d] overflow-hidden my-5 text-[0.8125rem] font-mono shadow-sm dark:shadow-[0_4px_24px_rgba(0,0,0,0.18)]">

      {}
      <div className="flex items-center justify-between py-2 px-[0.875rem] bg-[#f6f8fa] dark:bg-[#161b22] border-b border-[#d0d7de] dark:border-[#30363d]">
        <div className="flex items-center gap-2 text-[#656d76] dark:text-[#8b949e]">
          <svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor">
            <path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z" />
          </svg>
          <span className="text-xs font-medium text-[#1f2328] dark:text-[#e6edf3]">
            {fileName}
          </span>
        </div>
        {start && end && <span className="text-[0.6875rem] text-[#656d76] dark:text-[#8b949e] bg-[#eaeef2] dark:bg-[#21262d] border border-[#d0d7de] dark:border-[#30363d] rounded-full py-0.5 px-2">
            Lines {start}–{end}
          </span>}
      </div>

      {}
      <div className="overflow-auto max-h-[480px] bg-white dark:bg-[#0d1117] [&_tr]:border-b-0 [&_td]:border-b-0">
        {code === null ? <div className="py-5 px-4 text-xs text-[#656d76] dark:text-[#6e7681]">
            Loading...
          </div> : <table className="w-full border-collapse leading-[1.6]">
            <tbody>
              {code.split('\n').map((line, i) => <tr key={i} className="align-top border-0">
                  <td style={{
    minWidth: '60px'
  }} className="select-none pl-2 pr-3 text-right text-[0.7rem] text-[#8c959f] dark:text-[#3d444d] w-[1%] whitespace-nowrap border-r border-0 border-r-[#d0d7de] dark:border-r-[#21262d]">
                    {startLine + i}
                  </td>
                  <td className="pl-4 pr-6 text-[0.8125rem] text-[#1f2328] dark:text-[#e6edf3] whitespace-pre">
                    {line || ' '}
                  </td>
                </tr>)}
            </tbody>
          </table>}
      </div>

      {}
      {withSourceLink && <div className="flex justify-end py-1.5 px-[0.875rem] bg-[#f6f8fa] dark:bg-[#161b22] border-t border-[#d0d7de] dark:border-[#21262d]">
          <a href={sourceUrl} target="_blank" rel="noreferrer noopener" className="text-[0.6875rem] font-medium text-[#656d76] dark:text-[#8b949e] no-underline flex items-center gap-[0.3rem] hover:text-[#1f2328] dark:hover:text-[#e6edf3] transition-colors">
            View on GitHub
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
              <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
              <polyline points="15 3 21 3 21 9" />
              <line x1="10" y1="14" x2="21" y2="3" />
            </svg>
          </a>
        </div>}
    </div>;
};

In this page, we will explore strategies for reducing the size of smart contracts on NEAR. This is particularly useful for developers who want to optimize their contracts for deployment, especially in scenarios where contract size limits are a concern.

# Reducing a contract's size

<Tabs>
  <Tab title="🦀 Rust">
    ## Advice & examples

    This page is made for developers familiar with lower-level concepts who wish to reduce their contract size significantly, perhaps at the expense of code readability.

    Some common scenarios where this approach may be helpful:

    * contracts intended to be tied to one's account management
    * contracts deployed using a factory
    * future advancements similar to the EVM on NEAR

    There have been a few items that may add unwanted bytes to a contract's size when compiled. Some of these may be more easily swapped for other approaches while others require more internal knowledge about system calls.

    ## Small wins

    ### Using flags

    When compiling a contract make sure to pass flag `-C link-arg=-s` to the rust compiler:

    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release
    ```

    Here is the parameters we use for the most examples in `Cargo.toml`:

    ```toml theme={"theme":{"light":"github-light","dark":"github-dark"}}
    [profile.release]
    codegen-units = 1
    opt-level = "s"
    lto = true
    debug = false
    panic = "abort"
    overflow-checks = true
    ```

    You may want to experiment with using `opt-level = "z"` instead of `opt-level = "s"` to see if generates a smaller binary. See more details on this in [The Cargo Book Profiles section](https://doc.rust-lang.org/cargo/reference/profiles.html#opt-level). You may also reference this [Shrinking .wasm Size](https://rustwasm.github.io/book/reference/code-size.html#tell-llvm-to-optimize-for-size-instead-of-speed) resource.

    ### Removing `rlib` from the manifest

    Ensure that your manifest (`Cargo.toml`) doesn't contain `rlib` unless it needs to. Some NEAR examples have included this:

    <Warning>
      **Adds unnecessary bloat**

      ```toml theme={"theme":{"light":"github-light","dark":"github-dark"}}
      [lib]
      crate-type = ["cdylib", "rlib"]
      ```
    </Warning>

    when it could be:

    <Tip>
      ```toml theme={"theme":{"light":"github-light","dark":"github-dark"}}
      [lib]
      crate-type = ["cdylib"]
      ```
    </Tip>

    3. When using the Rust SDK, you may override the default JSON serialization to use [Borsh](https://borsh.io) instead. [See this page](./serialization-interface#overriding-serialization-protocol-default) for more information and an example.
    4. When using assertions or guards, avoid using the standard `assert` macros like [`assert!`](https://doc.rust-lang.org/std/macro.assert.html), [`assert_eq!`](https://doc.rust-lang.org/std/macro.assert_eq.html), or [`assert_ne!`](https://doc.rust-lang.org/std/macro.assert_ne.html) as these may add bloat for information regarding the line number of the error. There are similar issues with `unwrap`, `expect`, and Rust's `panic!()` macro.

    Example of a standard assertion:

    <Warning>
      **Adds unnecessary bloat**

      ```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
      assert_eq!(contract_owner, predecessor_account, "ERR_NOT_OWNER");
      ```
    </Warning>

    when it could be:

    <Tip>
      ```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
      if contract_owner != predecessor_account {
        env::panic(b"ERR_NOT_OWNER");
      }
      ```
    </Tip>

    Example of removing `expect`:

    <Warning>
      **Adds unnecessary bloat**

      ```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
      let owner_id = self.owner_by_id.get(&token_id).expect("Token not found");
      ```
    </Warning>

    when it could be:

    <Tip>
      ```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
      fn expect_token_found<T>(option: Option<T>) -> T {
        option.unwrap_or_else(|| env::panic_str("Token not found"))
      }
      let owner_id = expect_token_found(self.owner_by_id.get(&token_id));
      ```
    </Tip>

    Example of changing standard `panic!()`:

    <Warning>
      **Adds unnecessary bloat**

      ```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
      panic!("ERR_MSG_HERE");
      ```
    </Warning>

    when it could be:

    <Tip>
      ```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
      env::panic_str("ERR_MSG_HERE");
      ```
    </Tip>

    ## Ready to use script

    We have prepared a simple `bash` script that can be used to minify `.wasm` contract file. You can find it [here](https://github.com/near/near-sdk-rs/blob/master/minifier/minify.sh).

    The current approach to minification is the following:

    1. Snip (i.e. just replace with unreachable instruction) few known fat functions from the standard library (such as float formatting and panic-related) with `wasm-snip`.
    2. Run `wasm-gc` to eliminate all functions reachable from the snipped functions.
    3. Strip unneeded sections, such as names with `wasm-strip`.
    4. Run `binaryen wasm-opt`, which cleans up the rest.

    ### Requirements to run the script:

    * install [wasm-snip](https://docs.rs/wasm-snip/0.4.0/wasm_snip/) and [wasm-gc](https://docs.rs/crate/wasm-gc/0.1.6) with Cargo:

    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    cargo install wasm-snip wasm-gc
    ```

    * install [binaryen](https://github.com/WebAssembly/binaryen) and [wabt](https://github.com/WebAssembly/wabt) on your system. For Ubuntu and other Debian based Linux distributions run:

    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    apt install binaryen wabt
    ```

    <Danger>
      Minification could be rather aggressive, so you must test the contract after minification. Standalone NEAR runtime could be helpful [here](https://github.com/nearprotocol/nearcore/tree/master/runtime/near-vm-runner).
    </Danger>

    ## Lower-level approach

    For a `no_std` approach to minimal contracts, observe the following examples:

    * [Tiny contract](https://github.com/near/nearcore/tree/1e7c6613f65c23f87adf2c92e3d877f4ffe666ea/runtime/near-test-contracts/tiny-contract-rs)
    * [NEAR ETH Gateway](https://github.com/ilblackdragon/near-eth-gateway/blob/master/proxy/src/lib.rs)
    * [This YouTube video](https://youtu.be/Hy4VBSCqnsE) where Eugene demonstrates a fungible token in `no_std` mode. The code for this [example lives here](https://github.com/near/core-contracts/pull/88).
    * [Examples using a project called `nesdie`](https://github.com/austinabell/nesdie/tree/main/examples).
    * Note that Aurora has found success using [rjson](https://crates.io/crates/rjson) as a lightweight JSON serialization crate. It has a smaller footprint than [serde](https://crates.io/crates/serde) which is currently packaged with the Rust SDK. See [this example of rjson](https://github.com/aurora-is-near/aurora-engine/blob/65a1d11fcd16192cc1bda886c62005c603189a24/src/json.rs#L254) in an Aurora repository, although implementation details will have to be gleaned by the reader and won't be expanded upon here. [This nesdie example](https://github.com/austinabell/nesdie/blob/bb6beb77e32cd54077ac54bf028f262a9dfb6ad0/examples/multisig/src/utils/json/vector.rs#L26-L30) also uses the [miniserde crate](https://crates.io/crates/miniserde), which is another option to consider for folks who choose to avoid using the Rust SDK.

    <Note>
      **Information on system calls**

      <Accordion title="Expand to see what's available from <code>sys.rs</code>">
        <Github language="rust" url="https://github.com/near/near-sdk-rs/blob/master/near-sdk/src/environment/env.rs" />
      </Accordion>
    </Note>
  </Tab>

  <Tab title="🐍 Python">
    ## Optimizing Python Contracts

    Since Python smart contracts on NEAR are interpreted rather than compiled to WebAssembly directly, the optimization strategies differ from Rust contracts. The Python interpreter itself is already optimized, but you can still make your contract more efficient.

    ### Reducing Contract Size

    #### 1. Minimize Dependencies

    Only import the modules and functions you need:

    ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
    # Less efficient - imports everything
    from near_sdk_py import *

    # More efficient - imports only what's needed
    from near_sdk_py import view, call, Context
    ```

    #### 2. Use Efficient Data Structures

    Choose the right data structure for your needs:

    ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
    # Less efficient for lookups
    user_list = []  # O(n) lookup time
    for user in user_list:
        if user["id"] == user_id:
            return user

    # More efficient for lookups
    user_dict = {}  # O(1) lookup time
    if user_id in user_dict:
        return user_dict[user_id]
    ```

    #### 3. Optimize Storage Usage

    The NEAR SDK collections are optimized for on-chain storage. For large data sets, use these instead of native Python collections:

    ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
    # Native collection - loaded entirely into memory
    self.users = {}  # Loaded entirely on each method call

    # SDK collection - lazily loaded
    from near_sdk_py.collections import UnorderedMap
    self.users = UnorderedMap("u")  # Only loads what's needed
    ```

    #### 4. Reduce String Operations

    String operations can be expensive. Minimize them when possible:

    ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
    # Less efficient
    result = ""
    for i in range(100):
        result += str(i)  # Creates many intermediate strings

    # More efficient
    parts = []
    for i in range(100):
        parts.append(str(i))
    result = "".join(parts)  # Creates strings once
    ```

    #### 5. Avoid Recursion

    Deep recursion can lead to stack overflow issues. Consider iterative approaches instead:

    ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
    # Recursive - could cause issues with deep structures
    def process_tree(node):
        result = process_node(node)
        for child in node.children:
            result += process_tree(child)
        return result

    # Iterative - more efficient
    def process_tree(root):
        result = 0
        queue = [root]
        while queue:
            node = queue.pop(0)
            result += process_node(node)
            queue.extend(node.children)
        return result
    ```

    #### 6. Use Python's Built-in Functions

    Python's built-in functions are often optimized and more efficient:

    ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
    # Less efficient
    sum_value = 0
    for num in numbers:
        sum_value += num

    # More efficient
    sum_value = sum(numbers)
    ```

    #### 7. Split Complex Logic

    If you have a very large contract, consider splitting it into multiple contracts with focused responsibilities. This can improve maintainability and reduce the cost of individual calls.

    #### 8. Profile and Optimize Hot Paths

    Focus optimization efforts on the most frequently called functions or those that handle large amounts of data:

    ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
    @call
    def frequently_called_method(self, data):
        # Optimize this code carefully
        # Consider using more efficient algorithms and data structures
        pass
    ```
  </Tab>

  <Tab title="🐹 GO">
    ## Advice & examples

    Go contracts are compiled to WASM via **TinyGo**, which already applies aggressive size optimizations compared to the standard Go compiler. The `near-go build` command uses size-optimized TinyGo settings by default.

    Below are additional strategies to further reduce your contract size.

    ***

    ## Use `near-go build` (default)

    Always build with `near-go build` instead of raw `tinygo`. It applies the correct flags for NEAR and enables size optimizations automatically:

    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    near-go build
    ```

    To inspect the intermediate generated code or set a custom output name:

    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    near-go build --output my_contract.wasm --keep-generated
    ```

    ***

    ## Minimize struct fields

    Every field stored in the contract state is serialized to JSON. Keep your state structs lean — only store what you need on-chain.

    ```go theme={"theme":{"light":"github-light","dark":"github-dark"}}
    // Avoid: storing redundant or derived data
    // @contract:state
    type BadContract struct {
        Balance    string `json:"balance"`
        BalanceStr string `json:"balance_str"` // redundant — derive it when needed
        LastCaller string `json:"last_caller"`
        CallCount  uint64 `json:"call_count"`  // may not be necessary
    }

    // Better: store only essential state
    // @contract:state
    type GoodContract struct {
        Balance string `json:"balance"`
    }
    ```

    ***

    ## Avoid large dependencies

    TinyGo has a limited standard library. Avoid importing large packages that bring in code not needed at runtime. Prefer the SDK's built-in utilities:

    ```go theme={"theme":{"light":"github-light","dark":"github-dark"}}
    // Avoid: importing "fmt" for formatting — it adds significant size
    import "fmt"
    env.LogString(fmt.Sprintf("value: %d", x))

    // Better: use strconv or SDK helpers for simple conversions
    import "strconv"
    env.LogString("value: " + strconv.FormatUint(x, 10))
    ```

    ***

    ## Use SDK collections for large data

    Native Go slices and maps are fully serialized into the `STATE` key on every call, making the contract state grow with the collection. Use SDK collections to store entries as separate storage keys:

    ```go theme={"theme":{"light":"github-light","dark":"github-dark"}}
    import "github.com/vlmoon99/near-sdk-go/collections"

    // Avoid for large datasets: native map is fully loaded on every call
    // @contract:state
    type BadContract struct {
        Balances map[string]string `json:"balances"`
    }

    // Better: SDK LookupMap only loads entries on demand
    // @contract:state
    type GoodContract struct {
        Balances *collections.LookupMap[string, string] `json:"balances"`
    }
    ```

    ***

    ## Panic early, before doing expensive work

    Failing fast with `env.PanicStr` saves gas and avoids wasted computation. Validate all inputs and permissions before executing any logic:

    ```go theme={"theme":{"light":"github-light","dark":"github-dark"}}
    // @contract:mutating
    func (c *Contract) AdminAction(data string) {
        caller, _ := env.GetPredecessorAccountID()

        // Validate permissions immediately
        if caller != c.OwnerId {
            env.PanicStr("Only the owner can call this method")
        }

        // Validate input before processing
        if len(data) == 0 {
            env.PanicStr("Data must not be empty")
        }

        // ... proceed with the actual logic
    }
    ```

    <div style={{textAlign:"center",paddingBottom:"13px"}}><a style={{fontSize:"0.9em",fontWeight:600,color:"rgb(14, 117, 221)",textDecoration:"underline"}} href="https://github.com/Emir-Asanov/near-go-examples" target="_blank" rel="noreferrer noopener">See full example on GitHub</a></div>
  </Tab>
</Tabs>
