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.
Tenon Cloud: getting started
- Go to app.thetenon.com/auth and sign up with email or Google.
- 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.
- Invite teammates from Settings → Team members. Invitations arrive by email; the onboarding tour walks new people through projects, pages, chat and Brain.
- Create your first project, or import a Word/PDF document as a page to see the editor.
- 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.
- Optional, Business plan: connect SAML or OIDC from Settings → SSO and enforce it for your organization.
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
| Component | What Tenon needs | Notes |
|---|---|---|
| Backend | Supabase project (Cloud or self-hosted) | Postgres 15+, Auth, Realtime, Storage, Edge Functions, pg_cron |
| Frontend host | Any static file server or CDN | Nginx, Apache, Caddy, IIS, S3 + CloudFront, Cloudflare Pages… |
| Build machine | Node.js 20+ and the Supabase CLI | Only for building and deploying; not needed at runtime |
| An SMTP provider or Supabase's built-in email | For invitations and password resets | |
| AI (optional) | Gemini API key or an OpenAI-compatible endpoint | Configured 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
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>"
_shared/ai.ts module at call time.4. Configure auth & email
- 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. - Optional: enable Google as a provider with your OAuth client ID and secret.
- Configure SMTP under Authentication → SMTP Settings (or keep Supabase's default for low volume).
- 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
- Open your Tenon URL and sign up. The first account is promoted to superadmin.
- 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.
- Invite members by email from Settings → Team members. Invitations are sent through the SMTP you configured.
- 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.
- 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
- Read the release notes; they list any new migration, function or secret.
git pull,npm ci,npm run build, and replacedist/.supabase db pushfor new migrations;supabase functions deployfor changed functions.- Re-run the RLS self-test.
Team and Enterprise editions include upgrade support if anything in that list makes you nervous.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| Blank page after deploy | VITE_SUPABASE_URL or anon key missing at build time. Rebuild after editing .env. |
| Deep links return 404 | The SPA rewrite rule isn't active. Check step 5. |
| Invites never arrive | SMTP secrets not set on the function, or Site URL misconfigured. Run test-email. |
| "AI not configured" everywhere | Expected until a superadmin sets a provider in Admin Settings. |
| Standups don't post | pg_cron not enabled, or the cron job's service-role secret missing. |
| Google sign-in loops | Redirect 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.