develop solana smart contracts with gill
/Development

How to Build Solana Apps with Gill

9 min read

Gill is the newest JavaScript/TypeScript-based Solana developer tooling library. Originally developed by Nick Frostbutter, co-founder of Decal, while on the Solana Foundation's Developer Relations team, gill aims to significantly improve the developer experience for JavaScript-based applications.

Gill includes both lightly opinionated abstractions to accelerate developer productivity and lower-level primitives, providing developers the flexibility to choose their own approach.

The lightweight abstractions reduce many of the complexities and boilerplate required to perform common interactions with Solana. While the lower-level primitives provide "escape hatches" when developers need (or want) more fine-grain control over their application's logic.

This article will cover the basics of the "gill library", what's included in the library, how to get started with gill, and the differences between @solana/kit (formerly known as "web3.js v2").

What is Gill?

Gill is a modern TypeScript library for developing Solana applications on any JavaScript-based environment, ranging from the browser to the server to mobile.

The gill library is meant for Solana developers of all experience levels, from beginner to advanced. By shipping higher-level abstractions and the low-level primitives in the same package, developers can easily utilize the more advanced functionality when needed, or when it is not supported by the abstractions. 

The best part? 

Gill is fully tree-shakable, so your bundler will automatically remove any primitives or abstractions not used in your codebase.

Gill's primary goal is to improve developer experience by simplifying common Solana development tasks and removing boilerplate, without sacrificing the ability to get more low-level if a developer wants or needs to. Developers should not be limited to either high-level abstractions or low-level primitives. Developers should be able to easily choose either when it makes sense for them.

Installing Gill

Gill can be installed into any JavaScript or TypeScript-based project, including NodeJS/Bun, browser, React Native, or just about any other JavaScript environment.

Code
npm install gill

The gill library has strong TypeScript support and should work out of the box in most applications. However, your specific project's configuration may require tweaking to work better with gill. Consult the documentation for more info about TypeScript support in gill.

Gill vs. @solana/kit

The gill library is built directly on top of @solana/kit, the new low-level JavaScript primitives developed by Anza as a more performant replacement for the old @solana/web3.js.

While Kit only ships these low-level primitives, developers are forced into a single experience of manually crafting everything, resulting in ballooning applications with verbose boilerplate.

Enter gill.

Gill ships both the same low-level primitives as Kit and lightly opinionated abstractions to simplify common tasks, all from a single, compatible interface. By simplifying across the board with gill, developers can focus more time on their application's business logic and less time on verbose boilerplate.

Gill vs. Kit Code Examples

The following code snippets demonstrate how your code can be simplified while maintaining the same functionality (and potentially adding more). Nearly all applications will need to perform two tasks: establishing a connection to the blockchain and creating transactions.

Creating a connection to the blockchain with @solana/kit is done as follows:

Code
import {
  devnet,
  createSolanaRpc,
  createSolanaRpcSubscriptions,
  sendAndConfirmTransactionFactory,
} from "@solana/kit";

const rpc = createSolanaRpc(devnet("https://api.devnet.solana.com"));

const rpcSubscriptions = createSolanaRpcSubscriptions(
  devnet("wss://api.devnet.solana.com"),
);

const sendAndConfirmTransaction = sendAndConfirmTransactionFactory({
  rpc,
  rpcSubscriptions,
});

The same logic can be accomplished and simplified with gill's createSolanaClient function:

Code
import { createSolanaClient } from "gill";

const { rpc, rpcSubscriptions, sendAndConfirmTransaction } = createSolanaClient({
  urlOrMoniker: "devnet",
});

You can now make simple RPC requests using the rpc object created using either library in the examples above:

Code
// get the latest blockhash from your RPC provider
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();

Creating a simple transaction that includes a memo instruction with basic optimizations (using compute budget instructions) within @solana/kit is done as follows:

Code
import {
  pipe,
  createTransactionMessage,
  setTransactionMessageFeePayerSigner,
  appendTransactionMessageInstructions,
  setTransactionMessageLifetimeUsingBlockhash,
} from "@solana/kit";
import { getAddMemoInstruction } from "@solana-program/memo";
import {
  getSetComputeUnitLimitInstruction,
  getSetComputeUnitPriceInstruction,
} from "@solana-program/compute-budget";

const transaction = pipe(
  createTransactionMessage({ version: "legacy" }),
  (tx) => setTransactionMessageFeePayerSigner(signer, tx),
  (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
  (tx) =>
    appendTransactionMessageInstructions(
      [
        getAddMemoInstruction({
          memo: "gm world!",
        }),
        getSetComputeUnitLimitInstruction({ units: 5000 }),
        getSetComputeUnitPriceInstruction({ microLamports: 1000 }),
      ],
      tx,
    ),
);

The same logic can be greatly simplified using gill as follows:

Code
import { createTransaction } from "gill";
import { getAddMemoInstruction } from "gill/programs";

const transaction = createTransaction({
  version: "legacy",
  feePayer: signer,
  instructions: [
    getAddMemoInstruction({
      memo: "gm world!",
    }),
  ],
  latestBlockhash,
  computeUnitLimit: 5000,
  computeUnitPrice: 1000,
});

For a more comprehensive comparison between these two libraries, check out the gill documentation for gill vs @solana/kit.

What does the Kit to Gill migration process involve?

For any application using the @solana/kit library, the migration process to using the gill package is very straightforward:

  1. Install gill
  2. Replace all @solana/kit imports with gill
  3. Uninstall @solana/kit

Since gill also includes the most common Solana Program Library (SPL) clients directly, you can replace those package imports with gill too. Gill includes the following SPL clients directly accessible from the gill/programs import path:

  • @solana-program/system
  • @solana-program/memo
  • @solana-program/compute-budget
  • @solana-program/address-lookup-table
  • @solana-program/token-2022 (see note below about token program clients)

To utilize the single gill package for these SPL program clients:

  1. Replace the @solana-program/* package imports listed above with gill/programs
  2. Uninstall the @solana-program/* packages listed above.

After updating your imports, your application is immediately ready to start using the "gill core" library. You can now trivially refactor away the verbose Kit boilerplate (like creating blockchain connections and transactions) with any of the available gill abstractions.

What components are included with Gill?

The gill library can be broken down into a few key components:

  • Core functionality (aka "gill core")
  • Server runtime-specific helpers (i.e., NodeJS and Bun)
  • Program clients
  • Transaction builders
  • Debug mode

Node.js Helper Functions

The gill package includes several JavaScript server runtime-specific utilities. While they are included in the gill package, they have a separate import path to improve tree-shaking. These utilities include the ability to easily load and save keypairs to files or ENV variables.

Code
import { ... } from "gill/node"

To easily load a keypair file from your local filesystem (like the Solana CLI keypair):

Code
import { loadKeypairSignerFromFile } from "gill/node";

// default file path: ~/.config/solana/id.json
const signer = await loadKeypairSignerFromFile();
console.log("address:", signer.address);

You can also load a base58 encoded keypair from an ENV variable:

Code
import { loadKeypairSignerFromEnvironmentBase58 } from "gill/node";

// loads signer from base58 keypair stored at `process.env[variableName]`
const signer = await loadKeypairSignerFromEnvironmentBase58(variableName);
console.log("address:", signer.address);

Transaction Builders

To simplify the creation of common transactions that often interact with multiple programs at once, gill includes various "transaction builders" to help easily assemble ready-to-sign transactions for these tasks.

Since each transaction builder is scoped to a single task, it can easily abstract away various pieces of boilerplate while also helping to create an optimized transaction.

Some of the transaction builders that gill provides include:

Each transaction builder is accompanied by an "instruction builder" to improve developer flexibility for these gill abstractions.

Debug Mode

Within gill, you can enable "debug mode" to automatically log additional information that will help troubleshoot your transactions.

Debug mode is disabled by default to minimize additional logs from your application. With its flexible controller, you can enable debug mode from the most common places your code will run, including the code itself, NodeJS backends, serverless functions, and even in the web browser console.

To enable debug mode, set any of the following to true or 1:

  • process.env.GILL_DEBUG
  • global.__GILL_DEBUG__
  • window.__GILL_DEBUG__ (i.e. in your web browser's console)
  • or manually set any debug log level (see the docs)

Check out the gill Debug Mode docs for more information.

Complimentary Developer Tools for Building with Gill

gill-react

Directly inside the gill library is another package, gill-react, which is a collection of React hooks designed to radically improve the developer experience for React-based frontend applications. It's also built on-top of TanStack Query, a popular reactivity library, so it can be more easily utilized by existing applications.

The gill-react package is still in its infancy and under active development. It currently provides several useful React hooks for Solana applications:

Codama

Codama is a tool that allows developers to take a Solana program's IDL and generate client libraries (e.g., JavaScript, Rust) for use by other applications. Codama handles all the complexities of crafting Solana instructions into an IDL, a config file, and importing a function.

Gill and Codama easily integrate together with gill's createCodamaConfig function. The gill maintainer is also actively working to improve the gill<>Codama integration even further, including direct support in the Codama CLI!

By default, Codama-generated TypeScript program clients will use @solana/kit, but this can be easily updated in your Solana program's Codama configuration file. Upgrading to using gill in your Codama configuration is made trivial with the createCodamaConfig function.

The following is an example codama.js file that will generate a Solana program TypeScript client that uses gill:

Code
import { createCodamaConfig } from "gill";
 
export default createCodamaConfig({
  idl: "program/idl.json",
  clientJs: "clients/js/src/generated",
});

You can find a complete guide in the gill documentation for generating Solana program clients with Codama.

The Future of Gill

The future of the gill library is bright, and there is lots to do. The official gill documentation site has just launched, and the library is nearing 20,000 monthly downloads.

You can find more information about what is currently on the gill roadmap on the GitHub Projects page. At this time, the shortlist includes:

  • Direct support for the Solana Pay specification
  • Native integration of the Digital Assets Standard (DAS) API specification
  • Improved support for Token Extension-based tokens
  • Improved support for Address Lookup Tables
  • More comprehensive documentation

Included in the gill library, the gill-react package is in its infancy (with nine different React hooks). It is continuing to be built out to enable developers to easily add reactivity into their React-based applications, including support for all the common Solana RPC methods and a closer integration with wallet-ui.

Fun fact: There are plans to directly integrate gill into the Anchor framework to allow developers to more easily utilize gill's optimizations and developer experience improvements within their applications. Who knows, maybe gill will become the default in Anchor v2. :shhh:

How to Contribute to Gill

The gill library is open-source (MIT license) and contributors are welcome! If you are interested in contributing to the library, take a look at any open issues and consider tackling one yourself.

If you want to recommend a new feature or enhancement to the library, please open an issue first to begin a discussion with the maintainers before working on code for a PR.

Additional resources

Find more information and resources for gill at the following links:

Related Articles

Optimizing Solana Programs

A guide on Solana program optimization, covering Anchor to low-level unsafe Rust, balancing performance, safety, and usability.

Subscribe to Helius

Stay up-to-date with the latest in Solana development and receive updates when we post