Skip to main content

Web app design

Understand the table design for a basic web application.


Web applications are a great use case for storing data in tables. In particular, the Tableland Studio is a great tool for designing and managing your tables, and under the hood, it's just Tableland to store data. This guide will walk you through the basic table design for a web application and uses the Studio as a reference implementation.

Studio architecture

To set the stage, let's first review what the Studio uses. There are a total of 11 tables, each with a specific purpose. The primary design for a web app will typically include tables like teams, projects, and users.

The following provides a description Studio tables & a link to the actual deployed table data, or you can inspect the data interactively via the Studio itself (we imported these tables into the UI for data inspection purposes in this guide).

View the Tableland Studio deployment information & table descriptions
Table nameSchemaDescriptionLink
usersaddress text primary key not null,
team_id text unique not null,
sealed text not null
Tracks the users that have been created.users_42170_17
teamsid text primary key not null,
name text unique not null,
slug text unique not null,
personal integer not null
Tracks the teams that have been created.teams_42170_16
team_projectsteam_id text not null,
project_id text not null,
is_owner integer not null

With table constraint: unique(team_id, project_id)
Tracks the projects that have been created for a team.team_projects_42170_15
projectsid text primary key not null,
name text not null,
slug text not null,
description text not null
Tracks the projects that have been created.projects_42170_11
project_tablesproject_id text not null,
table_id text not null with constraint

With table constraint: unique(project_id, table_id)
Tracks the tables that have been created for a project.project_tables_42170_10
tablesid text primary key not null,
slug text not null,
name text not null,
description text not null,
schema text not null
Tracks the table blueprints that have been staged.tables_42170_12
deploymentstable_id text not null,
environment_id text not null,
table_name text not null,
chain_id integer not null,
token_id text not null,
block_number integer,
txn_hash text,
created_at text not null

With table constraint: primary key(environment_id, table_id)
Tracks the deployments that have been run where tables are live on a chain.deployments_42170_8
environmentsid text primary key not null,
project_id text not null,
name text not null,
slug text not null

With table constraint: unique(project_id, slug)
Tracks the environments that have been created.environments_42170_9
team_invitesid text primary key not null,
team_id text not null,
sealed text not null,
inviter_team_id text not null,
created_at text not null,
claimed_by_team_id text not null,
claimed_at text
Tracks the invites that have been sent to join a team.team_invites_42170_13
team_membershipsmember_team_id text not null,
team_id text not null,
is_owner integer not null,
joined_at text not null

With table constraint: unique(member_team_id, team_id)
Tracks the users that have joined a team.team_memberships_42170_14
migrationsid integer primary key,
file text not null unique,
hash not null
Tracks the migrations that have been run via Drizzle table migrations.migrations_42170_7

Table design

Of those described above, there are a few that are generally useful for any web application. All of these tables make use of a library like uuid to generate a unique identifier for each record within the application's logic. Additionally, it's quite common for a slug to be used, which would also be generated in the app logic to ensure uniqueness if a specific record is associated with a URL (e.g., https://example.com/my-team/my-project).

  • users: Tracks the users that have been created with a unique wallet address and their corresponding team ID.
  • teams: Tracks the teams that have been created.
  • team_projects: Tracks the projects that have been created for a team.
  • projects: Tracks the projects that have been created.
  • project_tables: Tracks some underlying data associated with a project—in this case, the tables that have been created for a project, but it could be anything!
caution

All data is public, so be careful what you store in your tables! For example, the actual Studio's implementation uses the concept of a "sealed" column that obfuscates private user information before inserting it into a table.

To recreate a similar setup as the Studio, we'd want to create the tables noted above:

CREATE TABLE users (
address text primary key not null,
team_id text unique not null
);

CREATE TABLE teams (
id text primary key not null,
name text unique not null,
slug text unique not null
);

CREATE TABLE team_projects (
team_id text not null,
project_id text not null
unique(team_id, project_id)
);

CREATE TABLE projects (
id text primary key not null,
name text not null,
slug text not null,
description text not null
);

CREATE TABLE project_tables (
project_id text not null,
table_id text not null,
unique(project_id, table_id)
);

After inserting some data, the resulting tables would look like this:

users

addressteam_id
0x1234...abcd-1234-efgh-1

teams

idnameslug
abcd-1234-efgh-1My Teammy-team

team_projects

team_idproject_id
abcd-1234-efgh-1wxyz-1234-efgh-2

projects

idnameslugdescription
wxyz-1234-efgh-2My Projectmy-projectDescription for project

project_tables

project_idtable_id
wxyz-1234-efgh-2000-111-abcd

Next steps

If you found this walkthrough helpful, check out the Studio itself to see how it's implemented! You can choose to deploy these tables within the Studio, too, and use the SDK to then interact with the data and your own application.