---
title: Work as a team
description: Create a workspace, invite people, publish into it, and share one warehouse connection without hitting the scope trap that publishes a dead dashboard.
updated: 2026-08-04
tier: pro
---

A workspace gives a group of people a shared URL prefix, shared dashboards,
shared folders, and one shared warehouse data source.

## Create a workspace

Open Settings, then **Workspaces**, and create one. You become its admin
automatically.

You choose the slug, and it becomes the subdomain your team's dashboards live at:
`https://<workspace-slug>.dashies.xyz/<slug>`. It must be 2 to 63 characters of
lower-case letters, digits, and hyphens, and may not start or end with a hyphen.

:::warning{title="Workspace slugs and user handles share one namespace"}
A workspace cannot be named after **any existing user handle, including your
own**. The refusal is:

```bash
slug already taken
```

This is the most surprising failure in workspace creation, and it is not a bug:
`<label>.dashies.xyz` has to resolve to exactly one thing, so a handle and a
workspace slug cannot both claim it. Sixteen infrastructure labels such as `www`,
`api`, and `docs` are also reserved.
:::

## Roles

There are two: **admin** and **member**. New people are added as members.

| Anyone in the workspace | Admins only |
|---|---|
| See the member list | Invite, change a role, remove someone else |
| Publish and republish workspace dashboards | Rename the workspace, change its logo, delete it |
| Restore and label a workspace dashboard's versions | Manage the workspace plan |
| See and edit the shared folder tree | Manage security: SSO, email domain, SCIM, audit |
| Author against a workspace data source | Delete, rotate, rename, resync, or re-test a workspace data source |
| Leave the workspace | |

You cannot demote or remove the last admin. Both refuse with
`cannot_demote_last_admin` or `cannot_remove_last_admin`. Promote someone else
first.

## Invite people

Settings, then the workspace's **Members** section. Invitees get a sign-in link
by email and land already added.

The result tells you which of four things happened:

| Result | Meaning |
|---|---|
| `invited` | We created an account for them and added them. |
| `added_existing_user` | They already had a Dashies account. Added. |
| `already_member` | Nothing to do. |
| `added_no_link` | The membership exists but the link could not be minted. Re-invite to retry. |

:::warning{title="Sent is not the same as delivered"}
A successful send means the email service accepted the request. It does **not**
confirm the message reached an inbox. "I invited them and nothing arrived" is a
delivery problem, not a membership problem: check the member list first, because
they are almost certainly already a member and can just sign in normally.
:::

Invites are rate-limited per email address, at roughly one a minute. Past that
you get `Too many invites - wait N s.` Re-clicking does not help, so wait.

The member list also shows a **last sign-in** time. That is the last sign-in, not
the last activity, so a colleague using Dashies daily on a long-lived session
will show an old date. An empty value means an invited account that has never
been used.

## Publish into a workspace

Your AI needs to be told which space to publish into. Two ways:

- Pass the workspace slug on the publish, which your AI does when you say so:

  > Publish that dashboard into the acme-analytics workspace.

- Or authorize a connection that is locked to that workspace, on the consent
  screen. See [Sign in and authorize](/guides/authorize).

Workspace dashboards default to **private**, meaning visible to members. Say so
explicitly if you want one public. See
[Share a dashboard](/guides/share-a-dashboard).

Any member may republish a workspace dashboard, including one they did not
create.

## Sharing a warehouse data source

This is the part that goes wrong most often, so it gets the most space.

A data source belongs permanently to the pair of **who created it** and **which
workspace they created it in**. Neither half can be changed afterwards, and there
is no move path in either direction. The reasoning is in
[scope is an immutable pair](/concepts/connections-and-scope#scope-is-an-immutable-pair).

Once it exists in a workspace:

- **Any current member can use it**, whoever created it, to author dashboards and
  bind them to it. The full permission split is in
  [what you can and cannot do with a connection](/concepts/connections-and-scope#what-you-can-and-cannot-do-with-a-connection). Current membership is required with no exemption for the
  creator, so someone removed from the workspace stops being able to author
  against the team's warehouse.
- **The creator, or any current admin, can change it**: delete, rotate, rename,
  resync, or re-test.

:::danger{title="A personal data source cannot back a workspace dashboard"}
To use a warehouse on team dashboards, **create it from inside that workspace**.
Open the workspace first, then add the data source. A personal one cannot be
moved into a workspace later. Full explanation:
[the workspace trap](/concepts/connections-and-scope#the-workspace-trap).

The refusal you hit if you get this wrong is:

```bash
source_config.connection is not an active warehouse connection available to this dashboard
```

That message is deliberately identical for an unknown id, an inactive data
source, a non-warehouse one, and a wrong-scope one, so it cannot be used to probe
what exists. If the id came straight out of your own connection list and the data
source is **active**, scope is the only remaining explanation, and the fix is to
publish into the data source's own workspace, or to point the dashboard at one
created in the space you are publishing into.

If the message instead says the connection is **not active**, that is a different
problem with a different fix: test it in the web app. Changing scope will not
help.
:::

:::danger{title="On a spec publish, the wrong scope does not stop the publish"}
This is the worst version of the trap, because everything looks like it worked.

The SQL validates, the seed runs against that very data source, and the dashboard
is **written and live at a real URL**. Only the refresh manifest is refused,
leaving a live dashboard that can never update. Your AI sees
`refresh installation failed` plus a sentence naming the mismatch.

A dry run does not catch it either. A dry run stops before the manifest is
installed, so a clean dry run is not evidence the data source is bindable in the
space you are publishing into.

**How to catch it:** after publishing into a workspace, check the dashboard has a
schedule and a next run. See the check at the bottom of this page.
:::

One more surface that reads oddly until you know why: listing your data sources
without naming a workspace returns your **personal** ones only. A workspace data
source you created yourself is not in that list. Ask for the workspace's list
instead. A non-member asking for a workspace's list gets an empty result rather
than an error, for the same anti-probing reason.

## Plans in a workspace

Your effective plan is the **best** of your own plan and the plans of the
workspaces you belong to. See
[what is gated](/concepts/plans-and-gating#what-is-gated).

So a free user who is a member of a Pro workspace has an effective Pro plan, and
their **personal** dashboards can refresh too. Adding someone to a paid workspace
does more than give them access to it.

## Teams inside a workspace

A team is a group of people inside a workspace with a name, a description, a
colour, and a screen of dashboards. Find them at
[dashies.xyz/app/teams](https://dashies.xyz/app/teams).

The important property: **a team screen references dashboards, it does not
contain them.** Removing a tile from a team screen removes the reference, never
the dashboard. One dashboard can appear on any number of team screens.

- A team is either **open**, visible to every workspace member, or **private**,
  visible only to its own members. Open is the default.
- Team membership is a subset of workspace membership, enforced by the database.
  Removing someone from the workspace removes them from every team automatically.
- Team names are scoped to the workspace, so two workspaces can each have a
  `sales` team.
- A private team whose last member leaves stays visible to workspace admins, so
  it is always recoverable.

## Check it worked

1. **The member sees it.** Ask a colleague to open the workspace dashboard URL.
   Your own view proves nothing, because you are a member too.
2. **The refresh is actually installed.** This is the check that catches the
   scope trap:

   > What is the refresh status of the `<slug>` dashboard in the acme-analytics
   > workspace?

   A working dashboard reports a schedule and a next run. **A dashboard that
   published fine but reports no schedule and no next run is the scope trap**, and
   the page will never update. Recreate the data source inside the workspace and
   republish.

3. **The data source is visible to the team.** Have another member list the
   workspace's data sources. If they see nothing, either they are not a member or
   the data source is personal.
4. **Confirm the last admin is safe.** Leaving a workspace with exactly one admin
   is refused, so check there are at least two before anyone with that role
   leaves.
