Solidity Libraries: Write Once, Use Everywhere

akindewaakindewa
3 min read

Solidity, the smart contract language of Ethereum,enables one to build decentralized applications that run on-chain. But as the codebase grows, it can quickly get messy by repeating the same logic across contracts, bloating bytecode, and making life harder than it needs to be.

That’s where libraries come in.

What Is a Library in Solidity?

A library in Solidity is like a toolbox: it’s a reusable collection of functions that can be shared by other contracts. You write the logic once in a library, and then call it from other contracts, thereby saving gas, reducing repetition, and keeping your code DRY (Don’t Repeat Yourself).

A practical example:

Library = A collection of read-only or stateless helpers
Contract = A full-blown smart contract that stores data and controls app logic

Solidity libraries are not meant to hold contract state (i.e., no storage variables) and cannot send Ether.

Why Use Libraries?

  • Reusability: One library, many contracts.

  • Gas Optimisation: Reduces bytecode duplication.

  • Clean Architecture: Keeps contracts smaller and focused.

  • Security: Avoid repeating bugs across multiple contracts.

Types of Libraries

There are two ways to use libraries in Solidity:

1. Embedded (Internal) Libraries

  • Functions are copied into the contract at compile time.

  • Cheaper to deploy since you don’t deploy the library separately.

  • Only allows internal functions.

library Math {
    function add(uint a, uint b) internal pure returns (uint) {
        return a + b;
    }
}

Usage:

contract Calculator {
    using Math for uint;

    function sum(uint a, uint b) public pure returns (uint) {
        return a.add(b);
    }
}

2. Deployed (External) Libraries

  • The library is deployed as a separate contract.

  • Can only use external or public functions.

  • Saves bytecode on each contract that uses it.

  • They must be linked to the library manually during deployment.

library MathExternal {
    function multiply(uint a, uint b) external pure returns (uint) {
        return a * b;
    }
}

Usage in contracts:

import "./MathExternal.sol";

contract UseExternal {
    function product(uint a, uint b) public pure returns (uint) {
        return MathExternal.multiply(a, b);
    }
}

Limitations of Libraries

  • No state variables allowed.

  • No Ether transfers.

  • Cannot inherit from other contracts or be inherited.

  • Cannot have fallback or receive functions.

They’re designed to be stateless, lean, and utility-focused.

Behind the Scenes: How Libraries Work

When using X for YSolidity internally changes how you call methods:

using Math for uint;
a.add(b);  // becomes Math.add(a, b);

Best Practices When Using Libraries

  • Grouping similar functions together (e.g., math, validation).

  • Using pure or view functions because they don’t modify state.

  • Marking functions as internal for embedded libraries.

  • Not using them to store state or transfer ETH.

  • Giving library files clear names like MathLib.sol or SafeTransferLib.sol.

FeatureInternal LibraryExternal Library
DeploymentEmbedded in contractDeployed separately
Function typesinternal onlypublic, external
Gas CostHigher per useLower (shared)
Use caseSimple helpersReusable large modules
3
Subscribe to my newsletter

Read articles from akindewa directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

akindewa
akindewa