Home

Awesome

Grist

Grist is a modern relational spreadsheet. It combines the flexibility of a spreadsheet with the robustness of a database.

The grist-core repo is the heart of Grist, including the hosted services offered by Grist Labs, an NYC-based company 🇺🇸 and Grist's main developer. The French government agency ANCT Données et Territoires 🇫🇷 has also made significant contributions to the codebase.

The grist-core, grist-desktop, and grist-static repositories are all open source (Apache License, Version 2.0).

Questions? Feedback? Want to share what you're building with Grist? Join our official Discord server or visit our Community forum.

https://user-images.githubusercontent.com/118367/151245587-892e50a6-41f5-4b74-9786-fe3566f6b1fb.mp4

Features

Grist is a hybrid database/spreadsheet, meaning that:

This difference can confuse people coming directly from Excel or Google Sheets. Give it a chance! There's also a Grist for Spreadsheet Users article to help get you oriented. If you're coming from Airtable, you'll find the model familiar (and there's also our Grist vs Airtable article for a direct comparison).

Here are some specific feature highlights of Grist:

If you are curious about where Grist is heading, see our roadmap, drop a question in our forum, or browse our extensive documentation.

Using Grist

If you just want a quick demo of Grist:

To get the default version of grist-core running on your computer with Docker, do:

docker pull gristlabs/grist
docker run -p 8484:8484 -it gristlabs/grist

Then visit http://localhost:8484 in your browser. You'll be able to create, edit, import, and export documents. To preserve your work across docker runs, share a directory as /persist:

docker run -p 8484:8484 -v $PWD/persist:/persist -it gristlabs/grist

Get templates at templates.getgrist.com for payroll, inventory management, invoicing, D&D encounter tracking, and a lot more, or use any document you've created on docs.getgrist.com.

If you need to change the port Grist runs on, set a PORT variable, don't just change the port mapping:

docker run --env PORT=9999 -p 9999:9999 -v $PWD/persist:/persist -it gristlabs/grist

To enable gVisor sandboxing, set --env GRIST_SANDBOX_FLAVOR=gvisor. This should work with default docker settings, but may not work in all environments.

You can find a lot more about configuring Grist, setting up authentication, and running it on a public server in our Self-Managed Grist handbook.

Available Docker images

The default Docker image is gristlabs/grist. This contains all of the standard Grist functionality, as well as extra source-available code for enterprise customers taken from the grist-ee repository. This extra code is not under a free or open source license. By default, however, the code from the grist-ee repository is completely inert and inactive. This code becomes active only when enabled from the administrator panel.

If you would rather use an image that contains exclusively free and open source code, the gristlabs/grist-oss Docker image is available for this purpose. It is by default functionally equivalent to the gristlabs/grist image.

The administrator panel

You can turn on a special admininistrator panel to inspect the status of your installation. Just visit /admin on your Grist server for instructions. Since it is useful for the admin panel to be available even when authentication isn't set up, you can give it a special access key by setting GRIST_BOOT_KEY.

docker run -p 8484:8484 -e GRIST_BOOT_KEY=secret -it gristlabs/grist

The boot page should then be available at /admin?boot-key=<GRIST_BOOT_KEY>. We are collecting probes for common problems there. If you hit a problem that isn't covered, it would be great if you could add a probe for it in BootProbes. You may instead file an issue so someone else can add it.

Building from source

To build Grist from source, follow these steps:

yarn install
yarn run build:prod
yarn run install:python
yarn start
# Grist will be available at http://localhost:8484/

Grist formulas in documents will be run using Python executed directly on your machine. You can configure sandboxing using a GRIST_SANDBOX_FLAVOR environment variable.

These sandboxing methods have been written for our own use at Grist Labs and may need tweaking to work in your own environment - pull requests very welcome here!

Logins

Like git, Grist has features to track document revision history. So for full operation, Grist expects to know who the user modifying a document is. Until it does, it operates in a limited anonymous mode. To get you going, the docker image is configured so that when you click on the "sign in" button Grist will attribute your work to you@example.com. Change this by setting GRIST_DEFAULT_EMAIL:

docker run --env GRIST_DEFAULT_EMAIL=my@email -p 8484:8484 -v $PWD/persist:/persist -it gristlabs/grist

You can change your name in Profile Settings in the User Menu.

For multi-user operation, or if you wish to access Grist across the public internet, you'll want to connect it to your own Single Sign-On service. There are a lot of ways to do this, including SAML and forward authentication. Grist has been tested with Authentik, Auth0, and Google/Microsoft sign-ins via Dex.

Translations

We use Weblate to manage translations. Thanks to everyone who is pitching in. Thanks especially to the ANCT developers who did the hard work of making a good chunk of the application localizable. Merci beaucoup !

<a href="https://hosted.weblate.org/engage/grist/"> <img src="https://hosted.weblate.org/widgets/grist/-/open-graph.png" alt="Translation status" width=480 /> </a>

Why free and open source software

This repository, grist-core, is maintained by Grist Labs. Our flagship product available at getgrist.com is built from the code you see here, combined with business-specific software designed to scale to many users, handle billing, etc.

Grist Labs is an open-core company. We offer Grist hosting as a service, with free and paid plans. We also develop and sell features related to Grist using a proprietary license, targeted at the needs of enterprises with large self-managed installations.

We see data portability and autonomy as a key value, and grist-core is an essential part of that. We are committed to maintaining and improving the grist-core codebase, and to be thoughtful about how proprietary offerings impact data portability and autonomy.

By opening its source code and offering an OSI-approved free license, Grist benefits its users:

For more on Grist Labs' history and principles, see our About Us page.

Sponsors

<p align="center"> <a href="https://www.dotphoton.com/"> <img width="11%" src="https://user-images.githubusercontent.com/11277225/228914729-ae581352-b37a-4ca8-b220-b1463dd1ade0.png" /> </a> </p>

Reviews

Environment variables

Grist can be configured in many ways. Here are the main environment variables it is sensitive to:

VariablePurpose
ALLOWED_WEBHOOK_DOMAINScomma-separated list of permitted domains to use in webhooks (e.g. webhook.site,zapier.com). You can set this to * to allow all domains, but if doing so, we recommend using a carefully locked-down proxy (see GRIST_HTTPS_PROXY) if you do not entirely trust users. Otherwise services on your internal network may become vulnerable to manipulation.
APP_DOC_URLdoc worker url, set when starting an individual doc worker (other servers will find doc worker urls via redis)
APP_DOC_INTERNAL_URLlike APP_DOC_URL but used by the home server to reach the server using an internal domain name resolution (like in a docker environment). It only makes sense to define this value in the doc worker. Defaults to APP_DOC_URL.
APP_HOME_URLurl prefix for home api (home and doc servers need this)
APP_HOME_INTERNAL_URLlike APP_HOME_URL but used by the home and the doc servers to reach any home workers using an internal domain name resolution (like in a docker environment). Defaults to APP_HOME_URL
APP_STATIC_URLurl prefix for static resources
APP_STATIC_INCLUDE_CUSTOM_CSSset to "true" to include custom.css (from APP_STATIC_URL) in static pages
APP_UNTRUSTED_URLURL at which to serve/expect plugin content.
GRIST_ADAPT_DOMAINset to "true" to support multiple base domains (careful, host header should be trustworthy)
GRIST_APP_ROOTdirectory containing Grist sandbox and assets (specifically the sandbox and static subdirectories).
GRIST_BACKUP_DELAY_SECSwait this long after a doc change before making a backup
GRIST_BOOT_KEYif set, offer diagnostics at /boot/GRIST_BOOT_KEY
GRIST_DATA_DIRDirectory in which to store documents. Defaults to docs/ relative to the Grist application directory. In Grist's default Docker image, its default value is /persist/docs so that it will be used as a mounted volume.
GRIST_DEFAULT_EMAILif set, login as this user if no other credentials presented
GRIST_DEFAULT_PRODUCTif set, this controls enabled features and limits of new sites. See names of PRODUCTS in Product.ts.
GRIST_DEFAULT_LOCALELocale to use as fallback when Grist cannot honour the browser locale.
GRIST_DOMAINin hosted Grist, Grist is served from subdomains of this domain. Defaults to "getgrist.com".
GRIST_EXPERIMENTAL_PLUGINSenables experimental plugins
GRIST_ENABLE_REQUEST_FUNCTIONenables the REQUEST function. This function performs HTTP requests in a similar way to requests.request. This function presents a significant security risk, since it can let users call internal endpoints when Grist is available publicly. This function can also cause performance issues. Unset by default.
GRIST_HIDE_UI_ELEMENTScomma-separated list of UI features to disable. Allowed names of parts: helpCenter,billing,templates,createSite,multiSite,multiAccounts,sendToDrive,tutorials,supportGrist. If a part also exists in GRIST_UI_FEATURES, it will still be disabled.
GRIST_HOSThostname to use when listening on a port.
GRIST_HTTPS_PROXYif set, use this proxy for webhook payload delivery.
GRIST_ID_PREFIXfor subdomains of form o-, expect or produce o-${GRIST_ID_PREFIX}.
GRIST_IGNORE_SESSIONif set, Grist will not use a session for authentication.
GRIST_INCLUDE_CUSTOM_SCRIPT_URLif set, will load the referenced URL in a <script> tag on all app pages.
GRIST_INST_DIRpath to Grist instance configuration files, for Grist server.
GRIST_LIST_PUBLIC_SITESif set to true, sites shared with the public will be listed for anonymous users. Defaults to false.
GRIST_MANAGED_WORKERSif set, Grist can assume that if a url targeted at a doc worker returns a 404, that worker is gone
GRIST_MAX_UPLOAD_ATTACHMENT_MBmax allowed size for attachments (0 or empty for unlimited).
GRIST_MAX_UPLOAD_IMPORT_MBmax allowed size for imports (except .grist files) (0 or empty for unlimited).
GRIST_OFFER_ALL_LANGUAGESif set, all translated langauages are offered to the user (by default, only languages with a special 'good enough' key set are offered to user).
GRIST_ORG_IN_PATHif true, encode org in path rather than domain
GRIST_PAGE_TITLE_SUFFIXa string to append to the end of the <title> in HTML documents. Defaults to " - Grist". Set to _blank for no suffix at all.
GRIST_PROXY_AUTH_HEADERDeprecated, and interpreted as a synonym for GRIST_FORWARD_AUTH_HEADER.
GRIST_ROUTER_URLoptional url for an api that allows servers to be (un)registered with a load balancer
GRIST_SERVE_SAME_ORIGINset to "true" to access home server and doc workers on the same protocol-host-port as the top-level page, same as for custom domains (careful, host header should be trustworthy)
GRIST_SERVERSthe types of server to setup. Comma separated values which may contain "home", "docs", static" and/or "app". Defaults to "home,docs,static".
GRIST_SESSION_COOKIEif set, overrides the name of Grist's cookie
GRIST_SESSION_DOMAINif set, associates the cookie with the given domain - otherwise defaults to GRIST_DOMAIN
GRIST_SESSION_SECRETa key used to encode sessions
GRIST_SKIP_BUNDLED_WIDGETSif set, Grist will ignore any bundled widgets included via NPM packages.
GRIST_ANON_PLAYGROUNDWhen set to 'false' deny anonymous users access to the home page
GRIST_FORCE_LOGINMuch like GRIST_ANON_PLAYGROUND but don't support anonymous access at all (features like sharing docs publicly requires authentication)
GRIST_SINGLE_ORGset to an org "domain" to pin client to that org
GRIST_TEMPLATE_ORGset to an org "domain" to show public docs from that org
GRIST_HELP_CENTERset the help center link ref
GRIST_TERMS_OF_SERVICE_URLif set, adds terms of service link
FREE_COACHING_CALL_URLset the link to the human help (example: email adress or meeting scheduling tool)
GRIST_CONTACT_SUPPORT_URLset the link to contact support on error pages (example: email adress or online form)
GRIST_SUPPORT_ANONif set to 'true', show UI for anonymous access (not shown by default)
GRIST_SUPPORT_EMAILif set, give a user with the specified email support powers. The main extra power is the ability to share sites, workspaces, and docs with all users in a listed way.
GRIST_TELEMETRY_LEVELthe telemetry level. Can be set to: off (default), limited, or full.
GRIST_THROTTLE_CPUif set, CPU throttling is enabled
GRIST_TRUST_PLUGINSif set, plugins are expect to be served from the same host as the rest of the Grist app, rather than from a distinct host. Ordinarily, plugins are served from a distinct host so that the cookies used by the Grist app are not automatically available to them. Enable this only if you understand the security implications.
GRIST_USER_ROOTan extra path to look for plugins in - Grist will scan for plugins in $GRIST_USER_ROOT/plugins.
GRIST_UI_FEATUREScomma-separated list of UI features to enable. Allowed names of parts: helpCenter,billing,templates,createSite,multiSite,multiAccounts,sendToDrive,tutorials,supportGrist. If a part also exists in GRIST_HIDE_UI_ELEMENTS, it won't be enabled.
GRIST_UNTRUSTED_PORTif set, plugins will be served from the given port. This is an alternative to setting APP_UNTRUSTED_URL.
GRIST_WIDGET_LIST_URLa url pointing to a widget manifest, by default https://github.com/gristlabs/grist-widget/releases/download/latest/manifest.json is used
GRIST_LOG_HTTPWhen set to true, log HTTP requests and responses information. Defaults to false.
GRIST_LOG_HTTP_BODYWhen this variable and GRIST_LOG_HTTP are set to true , log the body along with the HTTP requests. :warning: Be aware it may leak confidential information in the logs.:warning: Defaults to false.
COOKIE_MAX_AGEsession cookie max age, defaults to 90 days; can be set to "none" to make it a session cookie
HOME_PORTport number to listen on for REST API server; if set to "share", add API endpoints to regular grist port.
PORTport number to listen on for Grist server
REDIS_URLoptional redis server for browser sessions and db query caching
GRIST_SNAPSHOT_TIME_CAPoptional. Define the caps for tracking buckets. Usage: {"hour": 25, "day": 32, "isoWeek": 12, "month": 96, "year": 1000}
GRIST_SNAPSHOT_KEEPoptional. Number of recent snapshots to retain unconditionally for a document, regardless of when they were made
GRIST_PROMCLIENT_PORToptional. If set, serve the Prometheus metrics on the specified port number. ⚠️ Be sure to use a port which is not publicly exposed ⚠️.

AI Formula Assistant related variables (all optional):

VariablePurpose
ASSISTANT_API_KEYoptional. An API key to pass when making requests to an external AI conversational endpoint.
ASSISTANT_CHAT_COMPLETION_ENDPOINToptional. A chat-completion style endpoint to call. Not needed if OpenAI is being used.
ASSISTANT_MODELoptional. If set, this string is passed along in calls to the AI conversational endpoint.
ASSISTANT_LONGER_CONTEXT_MODELoptional. If set, requests that fail because of a context length limitation will be retried with this model set.
OPENAI_API_KEYoptional. Synonym for ASSISTANT_API_KEY that assumes an OpenAI endpoint is being used. Sign up for an account on OpenAI and then generate a secret key here.

At the time of writing, the AI Assistant is known to function against OpenAI chat completion endpoints for gpt-3.5-turbo and gpt-4. It can also function against the chat completion endpoint provided by <a href="https://github.com/abetlen/llama-cpp-python">llama-cpp-python</a>.

Sandbox related variables:

VariablePurpose
GRIST_SANDBOX_FLAVORcan be gvisor, pynbox, unsandboxed, docker, or macSandboxExec. If set, forces Grist to use the specified kind of sandbox.
GRIST_SANDBOXa program or image name to run as the sandbox. See NSandbox.ts for nerdy details.
PYTHON_VERSIONcan be 2 or 3. If set, documents without an engine setting are assumed to use the specified version of python. Not all sandboxes support all versions.
PYTHON_VERSION_ON_CREATIONcan be 2 or 3. If set, newly created documents have an engine setting set to python2 or python3. Not all sandboxes support all versions.

Forward authentication variables:

VariablePurpose
GRIST_FORWARD_AUTH_HEADERif set, trust the specified header (e.g. "x-forwarded-user") to contain authorized user emails, and enable "forward auth" logins.
GRIST_FORWARD_AUTH_LOGIN_PATHif GRIST_FORWARD_AUTH_HEADER is set, Grist will listen at this path for logins. Defaults to /auth/login.
GRIST_FORWARD_AUTH_LOGOUT_PATHif GRIST_FORWARD_AUTH_HEADER is set, Grist will forward to this path when user logs out.

Forward authentication supports two modes, distinguished by GRIST_IGNORE_SESSION:

  1. With sessions, and forward-auth on login endpoints.

    For example, using traefik reverse proxy with traefik-forward-auth middleware:

    • GRIST_IGNORE_SESSION: do NOT set, or set to a falsy value.
    • Make sure your reverse proxy applies the forward auth middleware to GRIST_FORWARD_AUTH_LOGIN_PATH and GRIST_FORWARD_AUTH_LOGOUT_PATH.
    • If you want to allow anonymous access in some cases, make sure all other paths are free of the forward auth middleware. Grist will trigger it as needed by redirecting to GRIST_FORWARD_AUTH_LOGIN_PATH. Once the user is logged in, Grist will use sessions to identify the user until logout.
  2. With no sessions, and forward-auth on all endpoints.

    For example, using HTTP Basic Auth and server configuration that sets the header (specified in GRIST_FORWARD_AUTH_HEADER) to the logged-in user.

When using forward authentication, you may wish to also set the following variables:

Plugins:

Grist has a plugin system, used internally. One useful thing you can do with it is include custom widgets in a build of Grist. Custom widgets are usually made available just by setting GRIST_WIDGET_LIST_URL, but that has the downside of being an external dependency, which can be awkward for offline use or for archiving. Plugins offer an alternative.

To "bundle" custom widgets as a plugin:

name: My Widgets
components:
  widgets: widgets.json

Google Drive integrations:

VariablePurpose
GOOGLE_CLIENT_IDset to the Google Client Id to be used with Google API client
GOOGLE_CLIENT_SECRETset to the Google Client Secret to be used with Google API client
GOOGLE_API_KEYset to the Google API Key to be used with Google API client (accessing public files)
GOOGLE_DRIVE_SCOPEset to the scope requested for Google Drive integration (defaults to drive.file)

Database variables:

VariablePurpose
TYPEORM_DATABASEdatabase filename for sqlite or database name for other db types
TYPEORM_HOSThost for db
TYPEORM_LOGGINGset to 'true' to see all sql queries
TYPEORM_PASSWORDpassword to use
TYPEORM_PORTport number for db if not the default for that db type
TYPEORM_TYPEset to 'sqlite' or 'postgres'
TYPEORM_USERNAMEusername to connect as
TYPEORM_EXTRAany other properties to pass to TypeORM in JSON format

Testing:

VariablePurpose
GRIST_TESTING_SOCKETa socket used for out-of-channel communication during tests only.
GRIST_TEST_HTTPS_OFFSETif set, adds https ports at the specified offset. This is useful in testing.
GRIST_TEST_SSL_CERTif set, contains filename of SSL certificate.
GRIST_TEST_SSL_KEYif set, contains filename of SSL private key.
GRIST_TEST_LOGINallow fake unauthenticated test logins (suitable for dev environment only).
GRIST_TEST_ROUTERif set, then the home server will serve a mock version of router api at /test/router
GREP_TESTSpattern for selecting specific tests to run (e.g. env GREP_TESTS=ActionLog yarn test).

Tests

Tests are run automatically as part of CI when a PR is opened. However, it can be helpful to run tests locally before pushing your changes to GitHub. First, you'll want to make sure you've installed all dependencies:

yarn install
yarn install:python

Then, you can run the main test suite like so:

yarn test

Python tests may also be run locally. (Note: currently requires Python 3.10 - 3.11.)

yarn test:python

For running specific tests, you can specify a pattern with the GREP_TESTS variable:

env GREP_TESTS=ChoiceList yarn test
env GREP_TESTS=summary yarn test:python

License

This repository, grist-core, is released under the Apache License, Version 2.0, which is an OSI-approved free software license. See LICENSE.txt and NOTICE.txt for more information.