A table becomes a page?

If I add a table:


It is then referred to as a page…


This becomes more evident when I can add widgets to what I thought was a table (well, I added it as a table):

And so, after having added a table it became a page and now it is a page with a widget:

This seems a bit confusing. What’s the difference between a table and a page? I think (thought?) that a table was the equivalent of a database table and a page is a view that can contain tables and other widgets. However, as soon as I add a table it is treated as a page and all dialogues that refer to actions on this table refer to a page rather than a table.

I can see that “Raw Data” shows the tables. The prior workflow seems a bit confusing and maybe even inconsistent. Perhaps it should be “Add a new page with a table widget” rather than “Add a table”?

Some of the question has to do with trying to understand how to create a Grist application where I am able to limit user interactions with the data through forms (cards?) and the underlying business-rules code, rather than the dangerous option of allowing them to directly edit or modify the actual tables.

Hello it’s easy
Table is Main data storage.
Page is a view of Table for representing data from this Table.
Simple example:
Table with different types of products
In table - Products we need to collect data for different types of products: Fruits, Cloth.
These products contain different characteristics, it is very difficult to use such a table to fill out; it can contain dozens of columns of characteristics for all products.
The simplest way is to create two pages for this table:
In which to hide/display columns with characteristics for each type of product and apply a filter by product type on each page.
When filling out products on the page, they will be added to the general table of products.
This is just a very simple application example.

I appreciate your response. However, this isn’t what I was asking. I am very familiar with relational databases, SQL, MySQL, PostgreSQL, SQLite, etc. Also well versed in Python, Pandas, Jupyter, Django and other frameworks.

My question is about what feels like an inconsistency in Grist. “Add New > Add Empty Table” actually appears to create a page with a single table widget in it, not a stand-alone table.


Grist is made thinking in easy of use.

The "Add New > Add Empty Table” is the third option. It’s a shortcut to "Add New > Add Page > Add Widget > New Table”

You have a button called CREATE NEW

Then you select the widget. Then you select the DATA SOURCE of the widget.

The data source can be an existing table OR a NEW TABLE.

When you create a NEW table, it creates a table PLUS a page with a table widget. Because it’s throught the table widget than you can modify your table.

In truth, the page and widget are independent from the table. You can delete the page and the table will remain.

Here, I create a new table/page called Example. As you first insert the name, it becomes the name of the table AND page

creating a “new” and selecting the table widget, I can create a new table, or use the table I created before (example)

When deleting a page that is the ONLY page showing a particular table, Grist asks you if you wish to delete the data table too or keep the data table.

Here, I created a second page that uses the SAME “example table”

Now, when I delete the original Example page, it doesn´t ask anymore if I wish to keep the data.

Grist always checks if there is at least ONE widget in any page using the table. If there is, it doesn´t ask if you want to remove the data table (because it’s being used). It only asks if you wish to keep the data table IF you remove the only widget showing it.

But again, you can delete all widgets or pages showing the data, and keep the data.

There it is… I removed all pages and widgets that used the Example Data Table. But I said I wanted to keep the data table.

It is still there, at Primary Data

When being accessed through PRIMARY DATA, you only see the data as a TABLE WIDGET. It works the same, except you can have your main menu cleaner, not having a menu entry to show it.

They did it thinking of as a shortcut for that longer path.
But I agree that maybe the Add New Table could go directly to Primary Data and the table view. Without adding a new page in the menu system.

Obrigado. That’s very useful and answers a few questions.

Of course, as I gain an understanding of Grist some of these inconsistencies will not matter. It is, however, strange to add a table and end-up with a page… because I just wanted to add a bunch of tables and import data into it, not expose them for editing.


I am thinking in terms of the application and my users. I don’t want a page for each table. I only want pages to expose the interface I need/want to expose to the underlying tables. And so, from my perspective, adding a table should do exactly that and nothing more. Just add a table, not a page with that table. It could, of course, have a checkbox to allow you to do both in one step. I think that would make it less confusing.

My suggestion would be to add a “Create page with this table as a widget” checkbox to this dialog:


It could be checked by default. In other words, no change to how it works now. This would make it more explicit and avoid confusion.

I have another question related to this. It deserves its own thread.

1 Like

I don’t want a page for each table. I only want pages to expose the interface I need/want to expose to the underlying tables. And so, from my perspective, adding a table should do exactly that and nothing more.

I see. Right now only thing you can do (it’s not that difficult anyway, but will require some 2-3 extra clicks for each table) is after importing the data and setting it all correctly, just delete the pages for each table and tell Grist to keep the data.

or better yet… don´t even delete the pages. Delete just the widgets connected to those tables inside the page and add the widgets for what you want.

Thanks again.

I was also thinking that user permissions might provide a good degree of control here. I haven’t explored this yet. I am completing the Lightweight CRM tutorial and reading through the documentation. I’m sure things will become much clearer as I learn more and continue to experiment.

1 Like

Yes, however, one of the missing (but on the roadmap if I am not mistaken) features of Grist is user permission for pages.

Right now, Grist can control user permissions for tables, rows and fields. But not pages.

That means that to block users from viewing a PAGE while still giving them access to a table, you need to create a helper table (can be a single row and column), and you will regulate permissions for that table. Then you will have that table as a widget inside any page you want to regulate what users can see.

Example… I created two tables here… a main table (Test Table) and an Options Table for status. The status column is a reference to Options table.

I also created a phony table to regulate access to pages. The page BLOCK has that table as a widget, alongside a widget showing the Options table and a widget repeating the Test Table (

Notice that I reduced the BLOCK table until I almost hid it

Also, I want to allow users to include new data in the referenced table.

But supposed the referenced table has lots of columns I don´t want most users to see data or edit data, but I need to allow them to add new options

So what I do is block all access to BLOCK TABLE (the helper table)

As soon as I clicked save, the entire page that had that widget showing the Block Table disappeared

In a real app, all pages with widgets showing block table would disappear from users without access to read the Block Table

On the main page however, you can still easily access data for the OPTIONS table

OK, I’ll play with this today. It is quite unfortunate that permissions cannot be controlled per page.

As I mentioned, I need separate permission-controlled applications for at least three classes of users: Sales, Operations and Engineering. There’s also a fourth class that should get a read-only application, this is the board of directors. They need to see what’s going on, what’s on the schedule, etc., yet not have the ability to change data.

I have to be honest, at some level it is starting to feel like this is currently beyond Grist and I should move on to a Python/Django implementation. I do want to learn Grist because I think it could be quite useful on many fronts as it exists today. In that spirit, I will attempt to complete the project in Grist this week and see what I end-up with. It’s a good tool. I might just be trying to use it outside the limits. That’s exactly what happened with the Excel-based version of this application they wrote a couple of years ago. Once it hit the limits (which happened quickly) there was no way to advance.

Hi @Martin_E.

Thanks for the feedback.

We’ve had some discussions internally about the separation of views (pages) and data (tables), and how we can improve things. Nothing specific to announce at this time, but we’re always thinking about ways we can improve the model, and your feedback helps us to better understand where to focus our attention.


1 Like

I think there should be a simpler, cruder permissions system directly on the table/columns level.

And preferably, at PAGE/WIDGET level too.

Sometimes, you want a user to have access to edit a table.

BUT you want to allow the user to edit a table seeing all the data, in a proper card format maybe.

Because you may use the same table as a widget, in another page, as a SELECTOR to another widget data.

And you don´t want that WIDGET to be editable. Exactly because it’s only to be used as a selector. People may end up clicking and editing it by accident.


If I were to compare what I have built so far with what I would have if I had implemented using Python + Django, I’d say that the Grist-based application is extremely fragile.

What I mean by this might be better explained by a comparison between using a touch screen vs. a control panel with real physical buttons and knobs for control. The touch screen version can be very dangerous because the probability of accidentally actuating the wrong buttons (one or many) is extremely high. Touch screens, in this sense, are not safe at all.

With what I know about Grist so far, it looks like it is hard to control user permissions with enough granularity to protect the underlying data from accidental modification.

With Django, I can produce forms and data views with as much granularity as necessary on a field-by-field basis.

In Grist, I am not sure I can define permission classes beyond the given Owner, Editor and Viewer categories. As a simple example, there is no reason for which a sales person should be able to edit formulas or Python code. They need to be assigned to a more restricted Editor-like category. There are also entire fields in different tables they should not be able to modify. One of the roles I have to implement is an Engineering role. They would be able to make changes to the definition of equipment sent out to customers. Right now, any Editor can trample all over what an engineer setup for a piece of equipment. Etc.

That said, I need to read more about Grist permissions and understand just how much more I might be able to do using Python to add granularity and control. In Access Rules, I don’t see a way to add user categories beyond Owner, Editor and Viewer. That’s a problem.

One thing that may help here is a User Attribute table. It does require you to set up a table in your Grist document to manage your users and their roles, but you’ll then be able to use those roles in access rules in place of the default Owner, Editor, and Viewer permissions.


Hi George.

While I have use the method of the User Attribute Table, that should be a default table listing all users included in the document, with editors being able to add columns, etc, but username and email should be automatic just by adding users to a document.

Maybe the table being hidden inside the Permissions menu.

Regarding my post before ( A table becomes a page? - #11 by Rogerio_Penna ), am I forgetting or missing something or is that right?

The permissions are at table level only right? If you give permission to a table, you can´t block permission for a user to edit that table at Widget level (like in my example, block editing data when the table is being used as a selector)

I guess that would be possible but require creating extra tables which replicate data from other table, and then blocking access to the second table… it can be done, but it’s uh… not optimal logic I think.

EDIT: I don´t know if it’s possible to keep two different tables synchronized to have the same number of rows. I can certainly pull all the records from table X to table Y, by using tableX.LookupOne(id=$id).tabXcolumn

But if I increase a row in table X, table Y won´t show that row until I manually add a new row in the second table

Right. Widget-level access rules would be handy, and we’ve received requests for it from other users in the past, but it’s not something that is possible now.

We made some designs in the past for a “V2” of Access Rules, which included a proper groups/roles management UI that would work across documents (that way, each document wouldn’t need its own table of users and groups/roles). Those designs were an overhaul of the existing Access Rules UI - focused on trying to make it easier to write rules, and reducing duplication of rules and user attributes. It’s not a project being actively worked on right this moment, but it’s one of a few bigger ones on our board, and it’d make sense to consider including support for widget-level rules as part of that project.


1 Like