Getting started

Two minutes on Cloud, or an afternoon self-hosted.

Start with Tenon Cloud if you just want to work. Follow the self-hosting guide if the software needs to run on your infrastructure, for your company, or for your departments and clients. The full product manual ships inside the app at /docs/manual.

Cloud: sign up and go Self-hosted: static host + Supabase, 1–2 hours Same product either way

Tenon Cloud: getting started

  1. Go to app.thetenon.com/auth and sign up with email or Google.
  2. Name your organization and choose a data region (EU or US). This can't be changed later without a migration, so pick where your data must live.
  3. Invite teammates from Settings → Team members. Invitations arrive by email; the onboarding tour walks new people through projects, pages, chat and Brain.
  4. Create your first project, or import a Word/PDF document as a page to see the editor.
  5. Optional: in Admin Settings → AI provider, connect Google Gemini (API key) or an OpenAI-compatible endpoint (base URL, model, key). Brain and the AI summaries switch on immediately.
  6. Optional, Business plan: connect SAML or OIDC from Settings → SSO and enforce it for your organization.
That's it. Backups, upgrades and monitoring are handled. Everything below this line is for teams running Tenon on their own infrastructure.

Self-hosting overview

Self-hosted Tenon is the same code Tenon Cloud runs. You deploy a static frontend bundle and a Supabase backend, then create one organization for your company, or, with the Enterprise edition, as many organizations as you have departments or clients, each isolated by Row Level Security and administered from the superadmin panel.

Requirements

ComponentWhat Tenon needsNotes
BackendSupabase project (Cloud or self-hosted)Postgres 15+, Auth, Realtime, Storage, Edge Functions, pg_cron
Frontend hostAny static file server or CDNNginx, Apache, Caddy, IIS, S3 + CloudFront, Cloudflare Pages…
Build machineNode.js 20+ and the Supabase CLIOnly for building and deploying; not needed at runtime
EmailAn SMTP provider or Supabase's built-in emailFor invitations and password resets
AI (optional)Gemini API key or an OpenAI-compatible endpointConfigured in-app by a superadmin

1. Create a Supabase project

Option A: Supabase Cloud. Create a project and pick the region your data must live in. Note the Project URL, the anon key and the service role key from Project Settings → API.

Option B: Self-hosted. Clone the Supabase Docker setup, set your secrets in .env, and start the stack:

git clone --depth 1 https://github.com/supabase/supabase
cd supabase/docker
cp .env.example .env      # set POSTGRES_PASSWORD, JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY, SITE_URL
docker compose up -d
Whichever option you choose, enable the pg_cron extension. Tenon's scheduled jobs (standups, briefings, webhook retries) run on it.

2. Apply the database schema

Tenon ships its schema as Supabase migrations. Link the CLI to your project and push them:

npm i -g supabase
supabase login                       # Cloud only
supabase link --project-ref <ref>    # or set SUPABASE_DB_URL for self-hosted
supabase db push

This creates every table with Row Level Security enabled and the org-scoped, superadmin-aware policies applied. Nothing is readable across organizations from this point on.

3. Deploy edge functions

The backend logic (public API, webhooks, invitations, AI calls and self-tests) runs as Deno edge functions:

supabase functions deploy api-v1
supabase functions deploy send-invite-email
supabase functions deploy create-team-member
supabase functions deploy webhook-dispatch
supabase functions deploy ai-chat
supabase functions deploy standup-digest
supabase functions deploy test-email
supabase functions deploy rls-self-test

Set the secrets the functions need (SMTP credentials, the service-role key for cron jobs):

supabase secrets set SMTP_HOST=… SMTP_USER=… SMTP_PASS=… SMTP_FROM="Tenon <no-reply@example.com>"
No AI key is set here. AI providers are configured in the app by a superadmin, stored per deployment, and read by the shared _shared/ai.ts module at call time.

4. Configure auth & email

  1. In Authentication → URL Configuration, set the Site URL to where Tenon will be served (e.g. https://work.example.com) and add it to the redirect allow-list.
  2. Optional: enable Google as a provider with your OAuth client ID and secret.
  3. Configure SMTP under Authentication → SMTP Settings (or keep Supabase's default for low volume).
  4. Run the test-email function to confirm delivery before inviting anyone:
curl -X POST "$SUPABASE_URL/functions/v1/test-email" \
  -H "Authorization: Bearer $SERVICE_ROLE_KEY" \
  -d '{"to":"you@example.com"}'

5. Build and serve the frontend

git clone https://github.com/tenon-app/tenon
cd tenon
cp .env.example .env
# VITE_SUPABASE_URL=https://<ref>.supabase.co
# VITE_SUPABASE_ANON_KEY=eyJ…
npm ci
npm run build          # -> dist/

Copy dist/ to your web server. Because Tenon is a single-page app, add one rewrite so deep links work:

Nginx

location / { try_files $uri $uri/ /index.html; }

Apache (.htaccess in dist/)

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [L]

Caddy

work.example.com {
  root * /var/www/tenon/dist
  try_files {path} /index.html
  file_server
}

6. First organization & AI provider

  1. Open your Tenon URL and sign up. The first account is promoted to superadmin.
  2. Create your first organization. Each organization is a fully isolated tenant. On the Enterprise edition, create one per client, department or subsidiary (there is no limit) and manage them all from the superadmin panel.
  3. Invite members by email from Settings → Team members. Invitations are sent through the SMTP you configured.
  4. In Admin Settings → AI provider, choose Google Gemini (API key + model) or OpenAI-compatible (base URL, model name, optional key). Save, then ask Brain something.
  5. Optional: connect a SAML or OIDC identity provider from Settings → SSO; the drawer shows every value your IdP asks for.

Verify the deployment

Run the RLS self-test. It creates two throwaway organizations, attempts cross-tenant reads and writes from each, and reports that every attempt was denied:

curl -X POST "$SUPABASE_URL/functions/v1/rls-self-test" \
  -H "Authorization: Bearer $SERVICE_ROLE_KEY"
# { "ok": true, "checks": 24, "denied": 24, "leaks": 0 }

Keep the output. It's the evidence your auditor will ask for.

Upgrading

  1. Read the release notes; they list any new migration, function or secret.
  2. git pull, npm ci, npm run build, and replace dist/.
  3. supabase db push for new migrations; supabase functions deploy for changed functions.
  4. Re-run the RLS self-test.

Team and Enterprise editions include upgrade support if anything in that list makes you nervous.

Troubleshooting

SymptomLikely cause
Blank page after deployVITE_SUPABASE_URL or anon key missing at build time. Rebuild after editing .env.
Deep links return 404The SPA rewrite rule isn't active. Check step 5.
Invites never arriveSMTP secrets not set on the function, or Site URL misconfigured. Run test-email.
"AI not configured" everywhereExpected until a superadmin sets a provider in Admin Settings.
Standups don't postpg_cron not enabled, or the cron job's service-role secret missing.
Google sign-in loopsRedirect URL not in the auth allow-list, or OAuth consent screen not published.

Stuck? Contact us or read the FAQ.

Rather not run servers?

Tenon Cloud is the same product with none of the steps above. Free for up to five members.