Admin & Setup Lesson 23 of 63 ⏱ 8 min ▶ Video

Multi-tenant setup walkthrough

Lesson summary

Everything from lessons 2–5 in one running scenario: two tenants sharing one instance, isolated from each other end-to-end. The "see it click" lesson.

By the end of this lesson

  • A working two-tenant configuration in your instance
  • A mental model for adding tenant N+1 without redesigning
  • A checklist you can return to when something looks off

You'll need

  • Admin role in DashboardFox
  • Lesson 25 complete (or at least understood — this lesson assembles them)
  • Branding planned (full version in Module 5)

Background

This lesson doesn't teach new mechanics. It assembles the four prior lessons (and previews branding from Module 5) into one running configuration: two tenants — a customer (Acme) and a partner (Partner Org) — sharing one DashboardFox instance, isolated from each other end-to-end.

When this lesson applies

You've decided you're multi-tenant — distinct customer organizations share one instance, and they should never see each other's data, branding, users, or schedule activity. If that's not your situation, the prior lessons are sufficient; this one is reference material for when your needs grow.

Quick checklist — the entire multi-tenant setup in one screen

If you've done this before and just need the reminder:

  • Tenant mode on (Settings → Server Settings)
  • Library folders default to All Users only — the canned-content distribution channel, plus optionally an admin-only folder for internal management
  • One group per tenant — never combined with other tenants
  • Each tenant's users assigned only to their tenant group with appropriate intra-group role
  • One root or sub-folder per tenant, assigned to that tenant's group only
  • Never mingle tenants in a group — All Users is the only legitimate shared group
  • One data tag per RLS value (e.g., tenantid) with per-group override per tenant — OR rely on Company profile tag set per user
  • One Data Security Policy per app referencing the tag (/#tenantid#/ or /#company#/)
  • Assign the RLS policy to All Users (ideally — covers every tenant automatically) or to every tenant group at minimum
  • Per-tenant branding if you want different visual experiences (Module 5)

Ongoing user creation once the foundation is in place is just three steps: create the user, assign to their tenant group with role, assign per-app roles.

The five moving pieces

Multi-tenant isolation is built from five layers working together. None of them alone is enough; together they make a tenant feel like they're the only customer in the system.

  • Tenant mode (lesson 5) — instance-level switch. User visibility scoped to shared groups; All Users folders become canned content.
  • Groups (lesson 3) — one per tenant, never mingled. Membership controls visibility, folder access, and branding scope.
  • Folder structure (lesson 3) — All Users folders for shared canned content; one parent folder per tenant for their private workspace.
  • Row-level security (lesson 4) — RLS policy with a constraint that scopes data per tenant. Profile tag (Company) or data tag (tenant_id) — either works.
  • Branding (Module 5) — per-group branding policies. Logo, colors, login domain, sidebar features. Optional, but where the "feels like a separate product" comes from.

Plus the foundation: users with the right per-app roles (lesson 2) and profile tag values set.

How the pieces connect

An at-a-glance diagram of how user, group, folder, report, app, and database relate:

  USER
  ├── identity, password
  ├── profile tags (company, tag1...) ──────┐  referenced by
  ├── group memberships                     │
  │     │                                   ▼
  │     │ member of               RLS POLICY
  │     ▼                         ├── constraint (column = value)
  │   TENANT GROUP                ├── value (/#company#/ or /#tenantid#/)
  │   ├── name (e.g., "Acme")     └── assigned groups (All Users ideally)
  │   ├── members
  │   └── target of folder perms
  │            │
  │            │ has View/Modify/Delete on
  │            ▼
  │       TENANT FOLDER
  │       ├── permissions: tenant group only
  │       └── stores reports
  │
  └── per-app role (Composer/Agent/App Builder)
              │
              │ runs reports against
              ▼
          APP (semantic layer)
              │
              │ created from
              ▼
        INTEGRATION (connection to data source)
              │
              ▼
          DATABASE

And the query path when a tenant user vs. an admin user runs the same canned report:

  Tenant user signs in              Admin user signs in
       │                                 │
       │ company = "ACME-001"            │ company = (not set)
       ▼                                 ▼
  Runs canned report                Runs canned report
       │                                 │
       │ RLS substitutes:                │ RLS substitutes:
       │   customer_id = 'ACME-001'      │   customer_id = ''
       ▼                                 ▼
  Query returns Acme rows           Query returns no rows
                                    (admins use admin-only reports
                                     against admin-only folders)

The key insight: a user passes through every layer for every query. Per-app role gates whether they can run anything; folder permissions gate whether they can open the report; RLS gates which rows come back. The same canned report serves every tenant; the user's tag values are what differentiate the results.

Haven't watched the video yet? Start there. About eight minutes; you'll see the same one report viewed by two tenants with completely different branding, completely different rows, and a scheduler that only shows their own users. This page is your reference for after — particularly the end-state checklist in Block 4.

Stuck assembling a multi-tenant configuration, or seeing one tenant leak into another? Email team@dashboardfox.com with your group structure and what's crossing the boundary. Real human, same business day.

Before you start

  • Tenant mode enabled (lesson 5). If it's off, the isolation patterns in this walkthrough don't work.
  • A tenant inventory. Write down each tenant's name, the group you'll create for them, the branding direction you want, and the data scope (a Company value or tenant ID) that identifies their rows.
  • A clear sense of shared vs. tenant-specific content. The shared content (canned reports every tenant sees) goes in All Users folders. Tenant-specific content goes in per-tenant folders.
  • An admin user outside any tenant group, so you can manage the configuration without being scoped by any tenant's RLS.
  • Time to verify as each tenant. Plan on five minutes per tenant for the verification loop — log out, log in, check folders, run a shared report, check scheduler.

Do it

  1. Confirm tenant mode is on

    Quick check: Settings → Server Settings → Enable Tenant Mode should be toggled on. If you haven't done lesson 5 yet, do that first. Tenant mode is the foundation everything else here builds on; without it, user visibility and folder management won't behave the way this walkthrough assumes.

  2. Create users with profile tags set

    For each tenant, create at least one user. For Acme: Acme User, with Company = Acme Corp. For Partner Org: Partner User, with Company = Partner Org.

    Pattern reminders from lesson 2:

    • Decide login convention upfront (handles or emails). Consistent across all tenants is much easier.
    • Fill in Company during creation — RLS will reference it as /#company#/.
    • Don't grant any per-app roles yet. That happens in step 7 once the groups exist.
  3. Create one group per tenant — never mingled

    Settings → Security → Groups → Create New Group. One group per tenant:

    • Customer Acme — members: Acme User. Intra-group role: View (or Modify if they should manage their own folders' subfolder structure).
    • Partner Org — members: Partner User. Intra-group role: View or Modify.

    The anti-pattern (the most common multi-tenant mistake): a single "Customers" or "External Users" group containing both Acme and Partner users. With tenant mode on, members of that group would see each other in scheduler dropdowns. One group per tenant. No exceptions. If you find yourself wanting to share a group across tenants, you actually want either (a) a folder permissioned to All Users — which all tenants see safely as canned content, or (b) per-tenant folders with the same shared report copied via Sync Server (Scale tier).

    Optionally, create an internal-staff group too — e.g., Customer Support Team with your support reps. This group can be permissioned to per-tenant folders (so your team can collaborate inside a tenant's workspace) without being part of any tenant's group themselves.

  4. Configure the data security policy with tenant scope

    Two paths from lesson 4 — either works for multi-tenant. Pick whichever fits how you provision users:

    • Profile tag path: use the Company value you set in step 2. Constraint: Customer field = /#company#/. Applied to All Users.
    • Data tag path: create a tenant_id data tag with default = a demo tenant. Per-group assignments: ACME for the Customer Acme group, PARTNER for the Partner Org group. Constraint: Customer field = /#tenant_id#/.

    Whichever path, keep all the app's constraints in one policy — multiple constraints in one policy compose as AND (most restrictive). Splitting into multiple policies gives you OR (less restrictive — almost never what you want for tenants).

    Test in this step before moving on: log in as Acme User, run a shared report, confirm only Acme rows return. Log in as Partner User, confirm only Partner rows. If RLS isn't working at this point, no other layer will save you — fix this first.

  5. Build the folder structure

    Three categories of folders for a typical multi-tenant setup:

    • All Users parent (e.g., Shared Reports) — the canned content every tenant sees. Permissioned to All Users. With tenant mode on, this is read-only for everyone but admins.
    • Per-tenant parent — one per tenant. Acme Reports permissioned only to Customer Acme group (plus your Customer Support Team if applicable). Partner Reports permissioned only to Partner Org. Each tenant manages their own workspace; other tenants can't see it exists.
    • Admin-only parent — optional. Permissioned to Administrators only. Audit reports, usage dashboards.

    In the shared parent, save the report(s) every tenant should see. RLS will filter the rows per tenant; tenant mode will keep the report read-only for non-admins. That's the canned-content pattern in action.

  6. Configure per-tenant branding (Module 5 preview)

    Branding is covered fully in Module 5, but it's the piece that turns "isolated from each other" into "feels like a separate product." Quick orientation:

    • Settings → Branding → Application Branding → Create New Branding. Two tabs at the top: Application and Guest (covered in Module 14).
    • Name the policy after the tenant (e.g., Acme Branding). Pick logo, colors, sidebar features (Feature Options, Sidebar Options, Dashboard Options accordions).
    • Assigned Groups — pick only the tenant's group. Acme branding → Customer Acme group only. Don't apply to All Users; you want different branding per tenant.
    • Create a corporate/default branding policy for your internal staff and the Administrators group (everyone else). Don't leave that group with un-branded defaults if you've built tenant brands.

    For full per-tenant isolation, you'll also want a custom domain per tenant (e.g., reports.acme.com for Acme users) so even their login screen is branded. That's an advanced branding feature — see Branding advanced.

  7. Assign per-app roles

    Edit each tenant user (Settings → Security → Users → Edit). In App Assignments, grant the role they need on each app:

    • Agent — view-only, the most common pattern for customer users who'll only run reports.
    • Composer — for tenant users who'll build their own reports inside their workspace. Their RLS still applies — they'll only see their tenant's data even in the report builder.
    • App Builder — almost never granted to tenant users. Reserved for your internal team.

    Don't grant Composer or App Builder on the same app the canned-content reports live on unless you actually want that tenant to be able to build their own reports. Many multi-tenant setups grant Agent across the board and let the canned content (plus the per-tenant folder for any custom requests) do all the work.

  8. Verify as each tenant

    Log out, log in as Acme User. Confirm:

    • Acme branding is in place (login screen if you have a custom domain; sidebar and app UI regardless).
    • Documents shows the All Users shared parent and the Acme Reports parent — not Partner Reports, not any admin folders.
    • The shared canned report runs and shows only Acme rows. The same report viewed by an admin shows all rows (or the default tenant if you've configured one).
    • Scheduling the report shows only Acme users (themselves, in this minimal setup) as available recipients.

    Repeat as Partner User — same checks, with Partner branding, Partner Reports folder, Partner rows in the report, Partner users in scheduling.

    Log in as your admin (outside any tenant group) and confirm you see everything. That's how you keep visibility into all tenants without being scoped by their RLS.

Make it real

Patterns that hold up as you add tenants 3, 5, 50.

The end-state checklist

Per tenant, you should be able to fill in this table:

Layer What you set
Users Created, with Company / tag values set
Group One per tenant, never mingled with other tenants
Tenant folder Parent permissioned only to the tenant's group (+ internal support if applicable)
RLS constraint Tag reference in the shared policy; rows filter per tenant
App roles Per user, per app — usually Agent across the board
Branding Tenant-specific policy assigned to tenant group only
Custom domain (optional) For branded login pages — advanced branding

Adding tenant N+1: copy this checklist, change the names and values, work top to bottom. Should take 15–20 minutes after the first one.

Canned content is the payoff

Worth restating: the value of this setup is that you build a report or dashboard once, in an All Users folder, and every tenant sees it filtered to their own data. Five tenants, ten tenants, a hundred tenants — one report.

The alternative — a separate report copy per tenant — multiplies your maintenance work by N. Every bug fix, every feature, every styling change has to happen N times. That model becomes unmaintainable fast.

The only practical alternative for per-tenant copies is the Sync Server feature on Scale tier, which keeps copies programmatically in sync. Canned content is simpler. Use Sync Server only when you genuinely need per-tenant report variants (e.g., different report layouts entirely, not just different data).

Keep a backup admin outside any tenant group

Same pattern as lesson 2, with an extra constraint for multi-tenant: the backup admin should not be a member of any tenant group. That keeps their visibility unscoped — they can see all tenants, all data, all activity, which is exactly what an emergency-access admin needs.

Tenant-specific admins (an admin per tenant) is a different pattern — covered in conversations with our team rather than baked into the default flow. If you need it, email us.

Audit-app review at a regular cadence

Multi-tenant configurations have more surface area for "an admin changed something and didn't tell anyone." The Audit App (Module 6) captures admin changes to RLS policies, group memberships, branding, and tenant mode. Build a monthly review into your operations — particularly after onboarding new admins.

When you outgrow the pattern

Two signals you've outgrown the basic multi-tenant pattern: (1) different tenants need genuinely different reports, not just different data — Sync Server (Scale tier) is the right tool; (2) tenants need to be able to bring their own data, separate from your shared models — you're moving toward a separate instance per tenant or our hosted multi-instance model. Either case is a conversation with our team rather than a configuration change.

You've reached the end of Module 4. Per-tenant branding is the natural next stop — Module 5 covers the basics; Branding advanced covers custom domains and per-tenant feature toggles.

If you're stuck

What goes wrong when assembling a multi-tenant configuration, in roughly the order it shows up.

Tenant A sees Tenant B's data in a shared report

RLS isn't applied or is misconfigured. Check (1) that the data security policy has a constraint on the report's category, (2) that the constraint's Custom Value references the right tag, (3) that both tenants have their tag values set correctly, (4) that the policy is assigned to All Users (or to both tenant groups). Verify by signing in as each tenant after every change.

Tenant A sees Tenant B's users in the scheduler dropdown

Tenant mode is off, or the tenants share a group. Confirm tenant mode is enabled in Server Settings. Check that no group contains members from multiple tenants — that's the most common cause, and it leaks regardless of any other configuration.

My new tenant sees no folders

You created the user but didn't add them to their tenant group, or their tenant group isn't permissioned to a folder. Walk back: is the user in Customer Acme group (or whatever)? Is there an Acme Reports folder permissioned to that group? Did you create at least one All Users folder so they see something shared? Refresh; folders appear.

Branding isn't applying for one tenant

The branding policy's Assigned Groups doesn't include the tenant's group. Edit the branding policy, confirm the right group is checked. Also confirm the policy is Active (toggle at the top of the branding form). If multiple branding policies could apply to the same user, scope matters — the most specific one usually wins, but verify.

My Composer (tenant user) can edit the shared canned-content folder

Tenant mode is off, or the folder isn't actually permissioned to All Users. With tenant mode on, All Users folders are read-only for Composers. If they can edit, the folder is probably permissioned directly to their group instead of (or in addition to) All Users.

Adding tenant N+1 is taking forever

Your first tenant takes 30–60 minutes. Tenants 2–N should be 15–20 minutes each. If you're taking longer, you're probably re-deciding architectural questions per tenant. The checklist in Block 4 is your script — copy, change names and values, work top to bottom.

An admin is seeing tenant-filtered data and can't see all tenants

The admin has a Company or tag value set that's matching the RLS constraint. Edit the admin user, clear the Company / tag fields (or set them to a value no row has, like ADMIN_BYPASS). With no matching value and a sensible RLS default, they'll see either everything or the demo default.

None of these match my situation

Email team@dashboardfox.com with your tenant inventory, the layer that's misbehaving, and a screenshot of the policy or group involved. Multi-tenant troubleshooting is much faster with the configuration in front of us. Same business day reply.

7-day free trial — no credit card

Built lean. Priced fairly. Supported by humans.

Full access to all features. No credit card required.

Prefer no subscriptions & full control? Self-hosted from $4,995 one-time →

Click once to extend to 14 days — need more time? Just reach out.

25+ years building BI tools Support from the team that builds it Available in US & EU regions
DashboardFox mascot