Skip to main content

Get started

Understand development prerequisites and how to get started with Tableland.

All database mutating statements are onchain actions. If you're using the SDK or CLI, much of the blockchain and smart contract specifics are abstracted away from the developer experience. If you're writing smart contracts, you're already familiar with the requirements around chains, accounts, and providers.


There are a few things every developer will need if they are trying to use Tableland:

  • Wallet: You'll need to set up an account, such as MetaMask for browser wallet-based connections. You'll use your EVM account's to create and write to tables across any of the networks Tableland is live on.
  • Funds: If you want to create or write to a table, it requires an onchain transaction—you need to own currency in the native chain's denomination if you want to make database state changes.
  • Chains & network concepts: Developers should be aware of fundamental network concepts like table naming convention, limits, and currently supported EVM chains.

If you're developing on a testnet, you should get testnet currency, and the way to do this depends on the chain you're using. Check out the chain selection documentation for how to use testnet faucets and get fake currency. Or, use Local Tableland to develop locally without having to worry about testnet currency.

Once you're ready to go, you can start building with any of the quickstarts or dive into subsequent deeper documentation! Note that the Tableland SDK (and the CLI built on top of it) use Node 18, so if you're using an older version of node, you'll have to implement the fetch and Header polyfills—check out the SDK docs for how to do this.

Local development

To make it easier to get started, you should check out the Local Tableland quickstart or dive deeper into the docs on how it works. It's, essentially, a sandboxed network running a local-only Tableland validator node, and a local-only Hardhat node in which Tableland registry smart contracts are deployed. So, you can develop and test your application locally without having to worry about deploying to a testnet or mainnet.

1. Installation & setup

First, set up your development environment. Within your project directory, run the following to install or use a Tableland package:

npm install @tableland/sdk ethers

This will let you use the Tableland SDK in your Node.js project as well as ethers for signer behavior. Or, you can choose to install a starter template—both JavaScript and TypeScript templates are available, so you'd choose one of the following:

git clone
git clone

Then, within your source code, set up Tableland; this will vary depending on the package you're using.

Here, we import and instantiate a Database, and in order to know the chain to connect to, we pass in a signer via a private key that will be used to connect to the chain.

import { Database } from "@tableland/sdk";
import { Wallet, getDefaultProvider } from "ethers";

// Connect to provider with a private key (e.g., via Hardhat)
const privateKey = "59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"; // Your private key
const wallet = new Wallet(privateKey);
const provider = getDefaultProvider(""); // Replace with the chain you want to connect to

// Pass the signer to the Database
const signer = wallet.connect(provider); // Uses the chain at the provider

2. Create a table

Let's create a simple my_table with two columns: id and val.

We'll use the run method to execute the query and await the transaction to finalize.

// Existing code from above

// Create a database connection
const db = new Database({ signer });

const { meta: create } = await db.prepare(`CREATE TABLE my_table (id int, val text);`).all();
await create.txn?.wait();
const [tableName] = create.txn?.names ?? [];

4. Write to a table

Now, we can write to the table created in the previous step.

We can insert a row into the table by calling the same prepare method and awaiting it to finish with the onchain transaction.

const { meta: write } = await db.prepare(`INSERT INTO my_table (id, val) VALUES (1, 'Bobby Tables');`).all();
await write.txn?.wait();

4. Read from a table

Lastly, we can read the materialized data from the table.

The results returned from the all method will be an array of objects where each object represents a table row.

const { results } = await db.prepare(`SELECT * FROM my_table;`).all();

Next steps

All of the subsequent pages go through each of these in more detail, so check them out if this initial walkthrough wasn't deep enough!